aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@users.noreply.github.com>2024-03-15 13:03:34 +0100
committerGitHub <noreply@github.com>2024-03-15 13:03:34 +0100
commit9338ef36ded767f2c35b7ec575b351859420ed09 (patch)
tree65c53c6a36f300859dc22b2d423275bcf2911367 /lib/public
parent6b09a79227a5dc98aa4620c6e5e15b610a06c806 (diff)
parentdf1cd1ba7e6e1f6e66a2b3229b5c082f1b81162e (diff)
downloadnextcloud-server-9338ef36ded767f2c35b7ec575b351859420ed09.tar.gz
nextcloud-server-9338ef36ded767f2c35b7ec575b351859420ed09.zip
Merge branch 'master' into refactor/OC-Server-getShareManager
Signed-off-by: John Molakvoæ <skjnldsv@users.noreply.github.com>
Diffstat (limited to 'lib/public')
-rw-r--r--lib/public/Accounts/IAccountManager.php53
-rw-r--r--lib/public/Activity/IExtension.php30
-rw-r--r--lib/public/App/IAppManager.php41
-rw-r--r--lib/public/App/ManagerEvent.php3
-rw-r--r--lib/public/AppFramework/ApiController.php8
-rw-r--r--lib/public/AppFramework/App.php4
-rw-r--r--lib/public/AppFramework/AuthPublicShareController.php6
-rw-r--r--lib/public/AppFramework/Bootstrap/IRegistrationContext.php43
-rw-r--r--lib/public/AppFramework/Controller.php2
-rw-r--r--lib/public/AppFramework/Http.php235
-rw-r--r--lib/public/AppFramework/Http/Attribute/ApiRoute.php63
-rw-r--r--lib/public/AppFramework/Http/Attribute/FrontpageRoute.php63
-rw-r--r--lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php1
-rw-r--r--lib/public/AppFramework/Http/Attribute/OpenAPI.php99
-rw-r--r--lib/public/AppFramework/Http/Attribute/Route.php161
-rw-r--r--lib/public/AppFramework/Http/ContentSecurityPolicy.php2
-rw-r--r--lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php44
-rw-r--r--lib/public/AppFramework/Http/ParameterOutOfRangeException.php79
-rw-r--r--lib/public/AppFramework/Http/Response.php7
-rw-r--r--lib/public/AppFramework/Http/TooManyRequestsResponse.php2
-rw-r--r--lib/public/AppFramework/OCSController.php23
-rw-r--r--lib/public/AppFramework/PublicShareController.php6
-rw-r--r--lib/public/AppFramework/Services/IAppConfig.php233
-rw-r--r--lib/public/AppFramework/Utility/ITimeFactory.php10
-rw-r--r--lib/public/Authentication/Exceptions/ExpiredTokenException.php49
-rw-r--r--lib/public/Authentication/Exceptions/InvalidTokenException.php33
-rw-r--r--lib/public/Authentication/Exceptions/WipeTokenException.php49
-rw-r--r--lib/public/Authentication/Token/IProvider.php15
-rw-r--r--lib/public/Authentication/Token/IToken.php139
-rw-r--r--lib/public/Authentication/TwoFactorAuth/IRegistry.php2
-rw-r--r--lib/public/BackgroundJob/IJobList.php20
-rw-r--r--lib/public/BackgroundJob/Job.php20
-rw-r--r--lib/public/Cache/CappedMemoryCache.php1
-rw-r--r--lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php1
-rw-r--r--lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php107
-rw-r--r--lib/public/Collaboration/Reference/IReference.php7
-rw-r--r--lib/public/Collaboration/Reference/LinkReferenceProvider.php221
-rw-r--r--lib/public/Collaboration/Reference/Reference.php2
-rw-r--r--lib/public/Comments/CommentsEntityEvent.php1
-rw-r--r--lib/public/Comments/CommentsEvent.php4
-rw-r--r--lib/public/Comments/IComment.php22
-rw-r--r--lib/public/Comments/ICommentsManager.php11
-rw-r--r--lib/public/Console/ConsoleEvent.php1
-rw-r--r--lib/public/Constants.php20
-rw-r--r--lib/public/Contacts/ContactsMenu/IBulkProvider.php40
-rw-r--r--lib/public/Contacts/ContactsMenu/IEntry.php14
-rw-r--r--lib/public/Contacts/ContactsMenu/IProvider.php7
-rw-r--r--lib/public/Contacts/IManager.php17
-rw-r--r--lib/public/DB/Events/AddMissingIndicesEvent.php41
-rw-r--r--lib/public/DB/QueryBuilder/IQueryBuilder.php9
-rw-r--r--lib/public/Dashboard/IManager.php2
-rw-r--r--lib/public/Dashboard/Model/WidgetButton.php11
-rw-r--r--lib/public/Dashboard/Model/WidgetItem.php10
-rw-r--r--lib/public/EventDispatcher/IEventDispatcher.php9
-rw-r--r--lib/public/Exceptions/AbortedEventException.php34
-rw-r--r--lib/public/Exceptions/AppConfigException.php34
-rw-r--r--lib/public/Exceptions/AppConfigIncorrectTypeException.php32
-rw-r--r--lib/public/Exceptions/AppConfigTypeConflictException.php32
-rw-r--r--lib/public/Exceptions/AppConfigUnknownKeyException.php32
-rw-r--r--lib/public/Federation/Exceptions/ActionNotSupportedException.php2
-rw-r--r--lib/public/Federation/Exceptions/AuthenticationFailedException.php2
-rw-r--r--lib/public/Federation/Exceptions/BadRequestException.php2
-rw-r--r--lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php2
-rw-r--r--lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php2
-rw-r--r--lib/public/Federation/ICloudFederationNotification.php4
-rw-r--r--lib/public/Federation/ICloudFederationProviderManager.php22
-rw-r--r--lib/public/Files/Cache/ICache.php15
-rw-r--r--lib/public/Files/Cache/ICacheEntry.php8
-rw-r--r--lib/public/Files/Cache/IScanner.php22
-rw-r--r--lib/public/Files/Cache/IUpdater.php2
-rw-r--r--lib/public/Files/Cache/IWatcher.php11
-rw-r--r--lib/public/Files/Config/ICachedMountInfo.php8
-rw-r--r--lib/public/Files/ConnectionLostException.php33
-rw-r--r--lib/public/Files/Events/FileCacheUpdated.php2
-rw-r--r--lib/public/Files/Events/Node/AbstractNodeEvent.php8
-rw-r--r--lib/public/Files/Events/Node/AbstractNodesEvent.php12
-rw-r--r--lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php9
-rw-r--r--lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php9
-rw-r--r--lib/public/Files/Events/NodeAddedToCache.php2
-rw-r--r--lib/public/Files/Events/NodeRemovedFromCache.php2
-rw-r--r--lib/public/Files/FileInfo.php18
-rw-r--r--lib/public/Files/Folder.php22
-rw-r--r--lib/public/Files/IHomeStorage.php8
-rw-r--r--lib/public/Files/IMimeTypeLoader.php8
-rw-r--r--lib/public/Files/IRootFolder.php30
-rw-r--r--lib/public/Files/LockNotAcquiredException.php2
-rw-r--r--lib/public/Files/Mount/IMountManager.php12
-rw-r--r--lib/public/Files/Node.php2
-rw-r--r--lib/public/Files/Notify/IChange.php15
-rw-r--r--lib/public/Files/Search/ISearchBinaryOperator.php11
-rw-r--r--lib/public/Files/Search/ISearchComparison.php60
-rw-r--r--lib/public/Files/Search/ISearchOrder.php20
-rw-r--r--lib/public/Files/Storage/INotifyStorage.php15
-rw-r--r--lib/public/Files/StorageAuthException.php2
-rw-r--r--lib/public/Files/StorageBadConfigException.php2
-rw-r--r--lib/public/Files/StorageConnectionException.php2
-rw-r--r--lib/public/Files/StorageNotAvailableException.php32
-rw-r--r--lib/public/Files/StorageTimeoutException.php2
-rw-r--r--lib/public/Files/Template/TemplateFileCreator.php1
-rw-r--r--lib/public/FilesMetadata/AMetadataEvent.php68
-rw-r--r--lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php40
-rw-r--r--lib/public/FilesMetadata/Event/MetadataLiveEvent.php67
-rw-r--r--lib/public/FilesMetadata/Event/MetadataNamedEvent.php74
-rw-r--r--lib/public/FilesMetadata/Exceptions/FilesMetadataException.php34
-rw-r--r--lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php32
-rw-r--r--lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php32
-rw-r--r--lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php32
-rw-r--r--lib/public/FilesMetadata/IFilesMetadataManager.php169
-rw-r--r--lib/public/FilesMetadata/IMetadataQuery.php92
-rw-r--r--lib/public/FilesMetadata/Model/IFilesMetadata.php386
-rw-r--r--lib/public/FilesMetadata/Model/IMetadataValueWrapper.php352
-rw-r--r--lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php35
-rw-r--r--lib/public/FullTextSearch/Model/IIndex.php60
-rw-r--r--lib/public/FullTextSearch/Model/IIndexDocument.php7
-rw-r--r--lib/public/FullTextSearch/Model/IRunner.php11
-rw-r--r--lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php43
-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.php35
-rw-r--r--lib/public/Http/Client/IClient.php41
-rw-r--r--lib/public/Http/WellKnown/JrdResponse.php8
-rw-r--r--lib/public/IAppConfig.php483
-rw-r--r--lib/public/ICacheFactory.php16
-rw-r--r--lib/public/IConfig.php6
-rw-r--r--lib/public/IDBConnection.php28
-rw-r--r--lib/public/IGroup.php60
-rw-r--r--lib/public/IMemcacheTTL.php19
-rw-r--r--lib/public/INavigationManager.php8
-rw-r--r--lib/public/IPhoneNumberUtil.php57
-rw-r--r--lib/public/IPreview.php7
-rw-r--r--lib/public/IURLGenerator.php5
-rw-r--r--lib/public/IUserManager.php6
-rw-r--r--lib/public/Log/Audit/CriticalActionPerformedEvent.php4
-rw-r--r--lib/public/Log/ILogFactory.php10
-rw-r--r--lib/public/Migration/IOutput.php7
-rw-r--r--lib/public/OCM/Events/ResourceTypeRegisterEvent.php62
-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.php165
-rw-r--r--lib/public/OCM/IOCMResource.php111
-rw-r--r--lib/public/Profile/IProfileManager.php106
-rw-r--r--lib/public/Search/FilterDefinition.php136
-rw-r--r--lib/public/Search/IFilter.php55
-rw-r--r--lib/public/Search/IFilterCollection.php57
-rw-r--r--lib/public/Search/IFilteringProvider.php72
-rw-r--r--lib/public/Search/IInAppSearch.php34
-rw-r--r--lib/public/Search/IProvider.php6
-rw-r--r--lib/public/Search/ISearchQuery.php14
-rw-r--r--lib/public/Search/SearchResult.php10
-rw-r--r--lib/public/Search/SearchResultEntry.php10
-rw-r--r--lib/public/Security/ISecureRandom.php23
-rw-r--r--lib/public/Security/RateLimiting/ILimiter.php72
-rw-r--r--lib/public/Security/RateLimiting/IRateLimitExceededException.php36
-rw-r--r--lib/public/Settings/DeclarativeSettingsTypes.php145
-rw-r--r--lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php105
-rw-r--r--lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php (renamed from lib/public/Dashboard/RegisterWidgetEvent.php)38
-rw-r--r--lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php87
-rw-r--r--lib/public/Settings/IDeclarativeManager.php92
-rw-r--r--lib/public/Settings/IDeclarativeSettingsForm.php81
-rw-r--r--lib/public/Settings/IManager.php38
-rw-r--r--lib/public/SetupCheck/ISetupCheck.php53
-rw-r--r--lib/public/SetupCheck/ISetupCheckManager.php37
-rw-r--r--lib/public/SetupCheck/SetupResult.php204
-rw-r--r--lib/public/Share.php94
-rw-r--r--lib/public/Share/Events/VerifyMountPointEvent.php4
-rw-r--r--lib/public/Share/IManager.php9
-rw-r--r--lib/public/Share/IShare.php6
-rw-r--r--lib/public/Share/IShareProvider.php2
-rw-r--r--lib/public/SpeechToText/ISpeechToTextProviderWithId.php14
-rw-r--r--lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php37
-rw-r--r--lib/public/SystemTag/ManagerEvent.php3
-rw-r--r--lib/public/SystemTag/MapperEvent.php2
-rw-r--r--lib/public/SystemTag/SystemTagsEntityEvent.php1
-rw-r--r--lib/public/Talk/IBroker.php4
-rw-r--r--lib/public/Talk/ITalkBackend.php4
-rw-r--r--lib/public/Teams/ITeamManager.php58
-rw-r--r--lib/public/Teams/ITeamResourceProvider.php76
-rw-r--r--lib/public/Teams/Team.php73
-rw-r--r--lib/public/Teams/TeamResource.php129
-rw-r--r--lib/public/TextProcessing/Exception/TaskFailureException.php10
-rw-r--r--lib/public/TextProcessing/IManager.php21
-rw-r--r--lib/public/TextProcessing/IProvider.php2
-rw-r--r--lib/public/TextProcessing/IProviderWithExpectedRuntime.php41
-rw-r--r--lib/public/TextProcessing/IProviderWithId.php39
-rw-r--r--lib/public/TextProcessing/IProviderWithUserId.php41
-rw-r--r--lib/public/TextProcessing/Task.php36
-rw-r--r--lib/public/TextToImage/Events/AbstractTextToImageEvent.php52
-rw-r--r--lib/public/TextToImage/Events/TaskFailedEvent.php54
-rw-r--r--lib/public/TextToImage/Events/TaskSuccessfulEvent.php33
-rw-r--r--lib/public/TextToImage/Exception/TaskFailureException.php31
-rw-r--r--lib/public/TextToImage/Exception/TaskNotFoundException.php31
-rw-r--r--lib/public/TextToImage/Exception/TextToImageException.php31
-rw-r--r--lib/public/TextToImage/IManager.php116
-rw-r--r--lib/public/TextToImage/IProvider.php64
-rw-r--r--lib/public/TextToImage/IProviderWithUserId.php15
-rw-r--r--lib/public/TextToImage/Task.php212
-rw-r--r--lib/public/Translation/ITranslationProviderWithId.php37
-rw-r--r--lib/public/Translation/ITranslationProviderWithUserId.php38
-rw-r--r--lib/public/User/Backend/IProvideEnabledStateBackend.php2
-rw-r--r--lib/public/User/Events/BeforePasswordUpdatedEvent.php4
-rw-r--r--lib/public/User/Events/BeforeUserCreatedEvent.php2
-rw-r--r--lib/public/User/Events/OutOfOfficeChangedEvent.php50
-rw-r--r--lib/public/User/Events/OutOfOfficeClearedEvent.php50
-rw-r--r--lib/public/User/Events/OutOfOfficeEndedEvent.php51
-rw-r--r--lib/public/User/Events/OutOfOfficeScheduledEvent.php50
-rw-r--r--lib/public/User/Events/OutOfOfficeStartedEvent.php51
-rw-r--r--lib/public/User/Events/PasswordUpdatedEvent.php4
-rw-r--r--lib/public/User/Events/UserChangedEvent.php6
-rw-r--r--lib/public/User/Events/UserCreatedEvent.php2
-rw-r--r--lib/public/User/Events/UserLiveStatusEvent.php4
-rw-r--r--lib/public/User/IAvailabilityCoordinator.php67
-rw-r--r--lib/public/User/IOutOfOfficeData.php94
-rw-r--r--lib/public/UserMigration/IImportSource.php3
-rw-r--r--lib/public/UserStatus/IManager.php4
-rw-r--r--lib/public/UserStatus/IUserStatus.php30
-rw-r--r--lib/public/Util.php99
-rw-r--r--lib/public/WorkflowEngine/IManager.php7
219 files changed, 8712 insertions, 394 deletions
diff --git a/lib/public/Accounts/IAccountManager.php b/lib/public/Accounts/IAccountManager.php
index 68eca469ad9..fbf2d831513 100644
--- a/lib/public/Accounts/IAccountManager.php
+++ b/lib/public/Accounts/IAccountManager.php
@@ -72,6 +72,7 @@ interface IAccountManager {
/**
* Contact details only visible locally
*
+ * @since 15.0.0
* @deprecated 21.0.1
*/
public const VISIBILITY_PRIVATE = 'private';
@@ -79,6 +80,7 @@ interface IAccountManager {
/**
* Contact details visible on trusted federated servers.
*
+ * @since 15.0.0
* @deprecated 21.0.1
*/
public const VISIBILITY_CONTACTS_ONLY = 'contacts';
@@ -86,6 +88,7 @@ interface IAccountManager {
/**
* Contact details visible on trusted federated servers and in the public lookup server.
*
+ * @since 15.0.0
* @deprecated 21.0.1
*/
public const VISIBILITY_PUBLIC = 'public';
@@ -105,14 +108,49 @@ interface IAccountManager {
self::VISIBILITY_PUBLIC,
];
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_AVATAR = 'avatar';
+
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_DISPLAYNAME = 'displayname';
+
+ /**
+ * @since 27.0.0
+ */
public const PROPERTY_DISPLAYNAME_LEGACY = 'display-name';
+
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_PHONE = 'phone';
+
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_EMAIL = 'email';
+
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_WEBSITE = 'website';
+
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_ADDRESS = 'address';
+
+ /**
+ * @since 15.0.0
+ */
public const PROPERTY_TWITTER = 'twitter';
+
+ /**
+ * @since 26.0.0
+ */
public const PROPERTY_FEDIVERSE = 'fediverse';
/**
@@ -161,10 +199,25 @@ interface IAccountManager {
self::PROPERTY_PROFILE_ENABLED,
];
+
+ /**
+ * @since 22.0.0
+ */
public const COLLECTION_EMAIL = 'additional_mail';
+ /**
+ * @since 15.0.0
+ */
public const NOT_VERIFIED = '0';
+
+ /**
+ * @since 15.0.0
+ */
public const VERIFICATION_IN_PROGRESS = '1';
+
+ /**
+ * @since 15.0.0
+ */
public const VERIFIED = '2';
/**
diff --git a/lib/public/Activity/IExtension.php b/lib/public/Activity/IExtension.php
index e02347f0373..23d96380c87 100644
--- a/lib/public/Activity/IExtension.php
+++ b/lib/public/Activity/IExtension.php
@@ -31,13 +31,43 @@ namespace OCP\Activity;
* @since 8.0.0
*/
interface IExtension {
+ /**
+ * @since 8.0.0
+ */
public const METHOD_STREAM = 'stream';
+
+ /**
+ * @since 8.0.0
+ */
public const METHOD_MAIL = 'email';
+
+ /**
+ * @since 20.0.0
+ */
public const METHOD_NOTIFICATION = 'notification';
+ /**
+ * @since 8.0.0
+ */
public const PRIORITY_VERYLOW = 10;
+
+ /**
+ * @since 8.0.0
+ */
public const PRIORITY_LOW = 20;
+
+ /**
+ * @since 8.0.0
+ */
public const PRIORITY_MEDIUM = 30;
+
+ /**
+ * @since 8.0.0
+ */
public const PRIORITY_HIGH = 40;
+
+ /**
+ * @since 8.0.0
+ */
public const PRIORITY_VERYHIGH = 50;
}
diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php
index 2497544dcbe..142e8bb8515 100644
--- a/lib/public/App/IAppManager.php
+++ b/lib/public/App/IAppManager.php
@@ -45,8 +45,8 @@ interface IAppManager {
/**
* Returns the app information from "appinfo/info.xml".
*
- * @param string $appId
- * @return mixed
+ * @param string|null $lang
+ * @return array|null
* @since 14.0.0
*/
public function getAppInfo(string $appId, bool $path = false, $lang = null);
@@ -62,10 +62,20 @@ interface IAppManager {
public function getAppVersion(string $appId, bool $useCache = true): string;
/**
+ * Returns the app icon or null if none is found
+ *
+ * @param string $appId
+ * @param bool $dark Enable to request a dark icon variant, default is a white icon
+ * @return string|null
+ * @since 29.0.0
+ */
+ public function getAppIcon(string $appId, bool $dark = false): string|null;
+
+ /**
* Check if an app is enabled for user
*
* @param string $appId
- * @param \OCP\IUser $user (optional) if not defined, the currently loggedin user will be used
+ * @param \OCP\IUser|null $user (optional) if not defined, the currently loggedin user will be used
* @return bool
* @since 8.0.0
*/
@@ -248,7 +258,30 @@ interface IAppManager {
*
* If `user` is not passed, the currently logged in user will be used
*
+ * @param ?IUser $user User to query default app for
+ * @param bool $withFallbacks Include fallback values if no default app was configured manually
+ * Before falling back to predefined default apps,
+ * the user defined app order is considered and the first app would be used as the fallback.
+ *
* @since 25.0.6
+ * @since 28.0.0 Added optional $withFallbacks parameter
+ */
+ public function getDefaultAppForUser(?IUser $user = null, bool $withFallbacks = true): string;
+
+ /**
+ * Get the global default apps with fallbacks
+ *
+ * @return string[] The default applications
+ * @since 28.0.0
+ */
+ public function getDefaultApps(): array;
+
+ /**
+ * Set the global default apps with fallbacks
+ *
+ * @param string[] $appId
+ * @throws \InvalidArgumentException If any of the apps is not installed
+ * @since 28.0.0
*/
- public function getDefaultAppForUser(?IUser $user = null): string;
+ public function setDefaultApps(array $defaultApps): void;
}
diff --git a/lib/public/App/ManagerEvent.php b/lib/public/App/ManagerEvent.php
index 0069e57db42..0853ce7981d 100644
--- a/lib/public/App/ManagerEvent.php
+++ b/lib/public/App/ManagerEvent.php
@@ -32,16 +32,19 @@ use OCP\EventDispatcher\Event;
*/
class ManagerEvent extends Event {
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_APP_ENABLE = 'OCP\App\IAppManager::enableApp';
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_APP_ENABLE_FOR_GROUPS = 'OCP\App\IAppManager::enableAppForGroups';
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_APP_DISABLE = 'OCP\App\IAppManager::disableApp';
diff --git a/lib/public/AppFramework/ApiController.php b/lib/public/AppFramework/ApiController.php
index 66c278e62d8..9505af0b2e2 100644
--- a/lib/public/AppFramework/ApiController.php
+++ b/lib/public/AppFramework/ApiController.php
@@ -52,10 +52,10 @@ abstract class ApiController extends Controller {
* @since 7.0.0
*/
public function __construct($appName,
- IRequest $request,
- $corsMethods = 'PUT, POST, GET, DELETE, PATCH',
- $corsAllowedHeaders = 'Authorization, Content-Type, Accept',
- $corsMaxAge = 1728000) {
+ IRequest $request,
+ $corsMethods = 'PUT, POST, GET, DELETE, PATCH',
+ $corsAllowedHeaders = 'Authorization, Content-Type, Accept',
+ $corsMaxAge = 1728000) {
parent::__construct($appName, $request);
$this->corsMethods = $corsMethods;
$this->corsAllowedHeaders = $corsAllowedHeaders;
diff --git a/lib/public/AppFramework/App.php b/lib/public/AppFramework/App.php
index 4d6e9177b78..f62c464ea55 100644
--- a/lib/public/AppFramework/App.php
+++ b/lib/public/AppFramework/App.php
@@ -38,6 +38,7 @@ use OC\AppFramework\Routing\RouteConfig;
use OC\Route\Router;
use OC\ServerContainer;
use OCP\Route\IRouter;
+use Psr\Log\LoggerInterface;
/**
* Class App
@@ -98,8 +99,9 @@ class App {
}
if (!$setUpViaQuery && $applicationClassName !== \OCP\AppFramework\App::class) {
- \OC::$server->getLogger()->logException($e, [
+ \OCP\Server::get(LoggerInterface::class)->error($e->getMessage(), [
'app' => $appName,
+ 'exception' => $e,
]);
}
}
diff --git a/lib/public/AppFramework/AuthPublicShareController.php b/lib/public/AppFramework/AuthPublicShareController.php
index 78dd45551ed..847f1823db8 100644
--- a/lib/public/AppFramework/AuthPublicShareController.php
+++ b/lib/public/AppFramework/AuthPublicShareController.php
@@ -57,9 +57,9 @@ abstract class AuthPublicShareController extends PublicShareController {
* @since 14.0.0
*/
public function __construct(string $appName,
- IRequest $request,
- ISession $session,
- IURLGenerator $urlGenerator) {
+ IRequest $request,
+ ISession $session,
+ IURLGenerator $urlGenerator) {
parent::__construct($appName, $request, $session);
$this->urlGenerator = $urlGenerator;
diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
index 720803a78d1..09bc703e0a4 100644
--- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
+++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php
@@ -37,10 +37,11 @@ use OCP\Collaboration\Reference\IReferenceProvider;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Template\ICustomTemplateProvider;
use OCP\IContainer;
-use OCP\TextProcessing\IProvider as ITextProcessingProvider;
use OCP\Notification\INotifier;
use OCP\Preview\IProviderV2;
use OCP\SpeechToText\ISpeechToTextProvider;
+use OCP\TextProcessing\IProvider as ITextProcessingProvider;
+use OCP\TextToImage\IProvider as ITextToImageProvider;
use OCP\Translation\ITranslationProvider;
/**
@@ -129,7 +130,7 @@ interface IRegistrationContext {
* @param string $event preferably the fully-qualified class name of the Event sub class to listen for
* @psalm-param string|class-string<T> $event preferably the fully-qualified class name of the Event sub class to listen for
* @param string $listener fully qualified class name (or ::class notation) of a \OCP\EventDispatcher\IEventListener that can be built by the DI container
- * @psalm-param class-string<\OCP\EventDispatcher\IEventListener> $listener fully qualified class name that can be built by the DI container
+ * @psalm-param class-string<\OCP\EventDispatcher\IEventListener<T>> $listener fully qualified class name that can be built by the DI container
* @param int $priority The higher this value, the earlier an event
* listener will be triggered in the chain (defaults to 0)
*
@@ -231,6 +232,16 @@ interface IRegistrationContext {
public function registerTextProcessingProvider(string $providerClass): void;
/**
+ * Register a custom text2image provider class that provides the possibility to generate images
+ * through the OCP\TextToImage APIs
+ *
+ * @param string $providerClass
+ * @psalm-param class-string<ITextToImageProvider> $providerClass
+ * @since 28.0.0
+ */
+ public function registerTextToImageProvider(string $providerClass): void;
+
+ /**
* Register a custom template provider class that is able to inject custom templates
* in addition to the user defined ones
*
@@ -341,6 +352,14 @@ interface IRegistrationContext {
public function registerCalendarRoomBackend(string $class): void;
/**
+ * @param string $class
+ * @psalm-param class-string<\OCP\Calendar\Room\IBackend> $actionClass
+ * @return void
+ * @since 29.0.0
+ */
+ public function registerTeamResourceProvider(string $class): void;
+
+ /**
* Register an implementation of \OCP\UserMigration\IMigrator that
* will handle the implementation of a migrator
*
@@ -371,4 +390,24 @@ interface IRegistrationContext {
* @since 26.0.0
*/
public function registerPublicShareTemplateProvider(string $class): void;
+
+ /**
+ * Register an implementation of \OCP\SetupCheck\ISetupCheck that
+ * will handle the implementation of a setup check
+ *
+ * @param class-string<\OCP\SetupCheck\ISetupCheck> $setupCheckClass
+ * @since 28.0.0
+ */
+ public function registerSetupCheck(string $setupCheckClass): void;
+
+ /**
+ * Register an implementation of \OCP\Settings\IDeclarativeSettings that
+ * will handle the implementation of declarative settings
+ *
+ * @param string $declarativeSettingsClass
+ * @psalm-param class-string<\OCP\Settings\IDeclarativeSettingsForm> $declarativeSettingsClass
+ * @return void
+ * @since 29.0.0
+ */
+ public function registerDeclarativeSettings(string $declarativeSettingsClass): void;
}
diff --git a/lib/public/AppFramework/Controller.php b/lib/public/AppFramework/Controller.php
index e8500d5ae1a..12e1c31626b 100644
--- a/lib/public/AppFramework/Controller.php
+++ b/lib/public/AppFramework/Controller.php
@@ -65,7 +65,7 @@ abstract class Controller {
* @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0
*/
public function __construct($appName,
- IRequest $request) {
+ IRequest $request) {
$this->appName = $appName;
$this->request = $request;
diff --git a/lib/public/AppFramework/Http.php b/lib/public/AppFramework/Http.php
index 8b3cde6875e..64e7fb689e5 100644
--- a/lib/public/AppFramework/Http.php
+++ b/lib/public/AppFramework/Http.php
@@ -29,63 +29,298 @@ namespace OCP\AppFramework;
* @since 6.0.0
*/
class Http {
+ /**
+ * @since 6.0.0
+ */
public const STATUS_CONTINUE = 100;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_SWITCHING_PROTOCOLS = 101;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_PROCESSING = 102;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_OK = 200;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_CREATED = 201;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_ACCEPTED = 202;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NON_AUTHORATIVE_INFORMATION = 203;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NO_CONTENT = 204;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_RESET_CONTENT = 205;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_PARTIAL_CONTENT = 206;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_MULTI_STATUS = 207;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_ALREADY_REPORTED = 208;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_IM_USED = 226;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_MULTIPLE_CHOICES = 300;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_MOVED_PERMANENTLY = 301;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_FOUND = 302;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_SEE_OTHER = 303;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NOT_MODIFIED = 304;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_USE_PROXY = 305;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_RESERVED = 306;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_TEMPORARY_REDIRECT = 307;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_BAD_REQUEST = 400;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_UNAUTHORIZED = 401;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_PAYMENT_REQUIRED = 402;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_FORBIDDEN = 403;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NOT_FOUND = 404;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_METHOD_NOT_ALLOWED = 405;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NOT_ACCEPTABLE = 406;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_REQUEST_TIMEOUT = 408;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_CONFLICT = 409;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_GONE = 410;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_LENGTH_REQUIRED = 411;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_PRECONDITION_FAILED = 412;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_REQUEST_ENTITY_TOO_LARGE = 413;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_REQUEST_URI_TOO_LONG = 414;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_UNSUPPORTED_MEDIA_TYPE = 415;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_EXPECTATION_FAILED = 417;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_IM_A_TEAPOT = 418;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_UNPROCESSABLE_ENTITY = 422;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_LOCKED = 423;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_FAILED_DEPENDENCY = 424;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_UPGRADE_REQUIRED = 426;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_PRECONDITION_REQUIRED = 428;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_TOO_MANY_REQUESTS = 429;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_INTERNAL_SERVER_ERROR = 500;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NOT_IMPLEMENTED = 501;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_BAD_GATEWAY = 502;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_SERVICE_UNAVAILABLE = 503;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_GATEWAY_TIMEOUT = 504;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_VARIANT_ALSO_NEGOTIATES = 506;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_INSUFFICIENT_STORAGE = 507;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_LOOP_DETECTED = 508;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NOT_EXTENDED = 510;
+
+ /**
+ * @since 6.0.0
+ */
public const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511;
}
diff --git a/lib/public/AppFramework/Http/Attribute/ApiRoute.php b/lib/public/AppFramework/Http/Attribute/ApiRoute.php
new file mode 100644
index 00000000000..0b566082521
--- /dev/null
+++ b/lib/public/AppFramework/Http/Attribute/ApiRoute.php
@@ -0,0 +1,63 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2024 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\AppFramework\Http\Attribute;
+
+use Attribute;
+
+/**
+ * This attribute can be used to define API routes on controller methods.
+ *
+ * It works in addition to the traditional routes.php method and has the same parameters
+ * (except for the `name` parameter which is not needed).
+ *
+ * @since 29.0.0
+ */
+#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
+class ApiRoute extends Route {
+ /**
+ * @inheritDoc
+ *
+ * @since 29.0.0
+ */
+ public function __construct(
+ protected string $verb,
+ protected string $url,
+ protected ?array $requirements = null,
+ protected ?array $defaults = null,
+ protected ?string $root = null,
+ protected ?string $postfix = null,
+ ) {
+ parent::__construct(
+ Route::TYPE_API,
+ $verb,
+ $url,
+ $requirements,
+ $defaults,
+ $root,
+ $postfix,
+ );
+ }
+}
diff --git a/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php b/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php
new file mode 100644
index 00000000000..ac08513a2a9
--- /dev/null
+++ b/lib/public/AppFramework/Http/Attribute/FrontpageRoute.php
@@ -0,0 +1,63 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2024 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\AppFramework\Http\Attribute;
+
+use Attribute;
+
+/**
+ * This attribute can be used to define Frontpage routes on controller methods.
+ *
+ * It works in addition to the traditional routes.php method and has the same parameters
+ * (except for the `name` parameter which is not needed).
+ *
+ * @since 29.0.0
+ */
+#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
+class FrontpageRoute extends Route {
+ /**
+ * @inheritDoc
+ *
+ * @since 29.0.0
+ */
+ public function __construct(
+ protected string $verb,
+ protected string $url,
+ protected ?array $requirements = null,
+ protected ?array $defaults = null,
+ protected ?string $root = null,
+ protected ?string $postfix = null,
+ ) {
+ parent::__construct(
+ Route::TYPE_FRONTPAGE,
+ $verb,
+ $url,
+ $requirements,
+ $defaults,
+ $root,
+ $postfix,
+ );
+ }
+}
diff --git a/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php
index 31ccd014321..4802ea5f1fd 100644
--- a/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php
+++ b/lib/public/AppFramework/Http/Attribute/IgnoreOpenAPI.php
@@ -31,6 +31,7 @@ use Attribute;
* Attribute for controller methods that should be ignored when generating OpenAPI documentation
*
* @since 28.0.0
+ * @deprecated 28.0.0 Use {@see OpenAPI} with {@see OpenAPI::SCOPE_IGNORE} instead: `#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]`
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
class IgnoreOpenAPI {
diff --git a/lib/public/AppFramework/Http/Attribute/OpenAPI.php b/lib/public/AppFramework/Http/Attribute/OpenAPI.php
new file mode 100644
index 00000000000..c5b3bcf5dda
--- /dev/null
+++ b/lib/public/AppFramework/Http/Attribute/OpenAPI.php
@@ -0,0 +1,99 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\AppFramework\Http\Attribute;
+
+use Attribute;
+
+/**
+ * With this attribute a controller or a method can be moved into a different
+ * scope or tag. Scopes should be seen as API consumers, tags can be used to group
+ * different routes inside the same scope.
+ *
+ * @since 28.0.0
+ */
+#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
+class OpenAPI {
+ /**
+ * APIs used for normal user facing interaction with your app,
+ * e.g. when you would implement a mobile client or standalone frontend.
+ *
+ * @since 28.0.0
+ */
+ public const SCOPE_DEFAULT = 'default';
+
+ /**
+ * APIs used to administrate your app's configuration on an administrative level.
+ * Will be set automatically when admin permissions are required to access the route.
+ *
+ * @since 28.0.0
+ */
+ public const SCOPE_ADMINISTRATION = 'administration';
+
+ /**
+ * APIs used by servers to federate with each other.
+ *
+ * @since 28.0.0
+ */
+ public const SCOPE_FEDERATION = 'federation';
+
+ /**
+ * Ignore this controller or method in all generated OpenAPI specifications.
+ *
+ * @since 28.0.0
+ */
+ public const SCOPE_IGNORE = 'ignore';
+
+ /**
+ * @param self::SCOPE_*|string $scope Scopes are used to define different clients.
+ * It is recommended to go with the scopes available as self::SCOPE_* constants,
+ * but in exotic cases other APIs might need documentation as well,
+ * then a free string can be provided (but it should be `a-z` only).
+ * @param ?list<string> $tags Tags can be used to group routes inside a scope
+ * for easier implementation and reviewing of the API specification.
+ * It defaults to the controller name in snake_case (should be `a-z` and underscore only).
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected string $scope = self::SCOPE_DEFAULT,
+ protected ?array $tags = null,
+ ) {
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getScope(): string {
+ return $this->scope;
+ }
+
+ /**
+ * @return ?list<string>
+ * @since 28.0.0
+ */
+ public function getTags(): ?array {
+ return $this->tags;
+ }
+}
diff --git a/lib/public/AppFramework/Http/Attribute/Route.php b/lib/public/AppFramework/Http/Attribute/Route.php
new file mode 100644
index 00000000000..58579c1f956
--- /dev/null
+++ b/lib/public/AppFramework/Http/Attribute/Route.php
@@ -0,0 +1,161 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2024 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\AppFramework\Http\Attribute;
+
+use Attribute;
+
+/**
+ * This attribute can be used to define routes on controller methods.
+ *
+ * It works in addition to the traditional routes.php method and has the same parameters
+ * (except for the `name` parameter which is not needed).
+ *
+ * @since 29.0.0
+ */
+#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
+class Route {
+
+ /**
+ * Corresponds to the `ocs` key in routes.php
+ *
+ * @see ApiRoute
+ * @since 29.0.0
+ */
+ public const TYPE_API = 'ocs';
+
+ /**
+ * Corresponds to the `routes` key in routes.php
+ *
+ * @see FrontpageRoute
+ * @since 29.0.0
+ */
+ public const TYPE_FRONTPAGE = 'routes';
+
+ /**
+ * @param string $type Either Route::TYPE_API or Route::TYPE_FRONTPAGE.
+ * @psalm-param Route::TYPE_* $type
+ * @param string $verb HTTP method of the route.
+ * @psalm-param 'GET'|'HEAD'|'POST'|'PUT'|'DELETE'|'OPTIONS'|'PATCH' $verb
+ * @param string $url The path of the route.
+ * @param ?array<string, string> $requirements Array of regexes mapped to the path parameters.
+ * @param ?array<string, mixed> $defaults Array of default values mapped to the path parameters.
+ * @param ?string $root Custom root. For OCS all apps are allowed, but for index.php only some can use it.
+ * @param ?string $postfix Postfix for the route name.
+ * @since 29.0.0
+ */
+ public function __construct(
+ protected string $type,
+ protected string $verb,
+ protected string $url,
+ protected ?array $requirements = null,
+ protected ?array $defaults = null,
+ protected ?string $root = null,
+ protected ?string $postfix = null,
+ ) {
+ }
+
+ /**
+ * @return array{
+ * verb: string,
+ * url: string,
+ * requirements?: array<string, string>,
+ * defaults?: array<string, mixed>,
+ * root?: string,
+ * postfix?: string,
+ * }
+ * @since 29.0.0
+ */
+ public function toArray() {
+ $route = [
+ 'verb' => $this->verb,
+ 'url' => $this->url,
+ ];
+
+ if ($this->requirements !== null) {
+ $route['requirements'] = $this->requirements;
+ }
+ if ($this->defaults !== null) {
+ $route['defaults'] = $this->defaults;
+ }
+ if ($this->root !== null) {
+ $route['root'] = $this->root;
+ }
+ if ($this->postfix !== null) {
+ $route['postfix'] = $this->postfix;
+ }
+
+ return $route;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getType(): string {
+ return $this->type;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getVerb(): string {
+ return $this->verb;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getUrl(): string {
+ return $this->url;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getRequirements(): ?array {
+ return $this->requirements;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getDefaults(): ?array {
+ return $this->defaults;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getRoot(): ?string {
+ return $this->root;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getPostfix(): ?string {
+ return $this->postfix;
+ }
+}
diff --git a/lib/public/AppFramework/Http/ContentSecurityPolicy.php b/lib/public/AppFramework/Http/ContentSecurityPolicy.php
index f17dd9bd270..7f93f7004d9 100644
--- a/lib/public/AppFramework/Http/ContentSecurityPolicy.php
+++ b/lib/public/AppFramework/Http/ContentSecurityPolicy.php
@@ -48,6 +48,8 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
protected ?bool $evalWasmAllowed = false;
/** @var bool Whether strict-dynamic should be set */
protected $strictDynamicAllowed = false;
+ /** @var bool Whether strict-dynamic should be set for 'script-src-elem' */
+ protected $strictDynamicAllowedOnScripts = true;
/** @var array Domains from which scripts can get loaded */
protected $allowedScriptDomains = [
'\'self\'',
diff --git a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php
index 7e1de2ef2eb..6662a302d7f 100644
--- a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php
+++ b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php
@@ -37,10 +37,12 @@ namespace OCP\AppFramework\Http;
* @since 9.0.0
*/
class EmptyContentSecurityPolicy {
- /** @var string Whether JS nonces should be used */
- protected $useJsNonce = null;
+ /** @var ?string JS nonce to be used */
+ protected ?string $jsNonce = null;
/** @var bool Whether strict-dynamic should be used */
protected $strictDynamicAllowed = null;
+ /** @var bool Whether strict-dynamic should be used on script-src-elem */
+ protected $strictDynamicAllowedOnScripts = null;
/**
* @var bool Whether eval in JS scripts is allowed
* TODO: Disallow per default
@@ -94,6 +96,18 @@ class EmptyContentSecurityPolicy {
}
/**
+ * In contrast to `useStrictDynamic` this only sets strict-dynamic on script-src-elem
+ * Meaning only grants trust to all imports of scripts that were loaded in `<script>` tags, and thus weakens less the CSP.
+ * @param bool $state
+ * @return EmptyContentSecurityPolicy
+ * @since 28.0.0
+ */
+ public function useStrictDynamicOnScripts(bool $state = false): self {
+ $this->strictDynamicAllowedOnScripts = $state;
+ return $this;
+ }
+
+ /**
* Use the according JS nonce
* This method is only for CSPMiddleware, custom values are ignored in mergePolicies of ContentSecurityPolicyManager
*
@@ -102,7 +116,7 @@ class EmptyContentSecurityPolicy {
* @since 11.0.0
*/
public function useJsNonce($nonce) {
- $this->useJsNonce = $nonce;
+ $this->jsNonce = $nonce;
return $this;
}
@@ -446,29 +460,37 @@ class EmptyContentSecurityPolicy {
$policy .= "base-uri 'none';";
$policy .= "manifest-src 'self';";
- if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed || $this->evalWasmAllowed) {
+ if (!empty($this->allowedScriptDomains) || $this->evalScriptAllowed || $this->evalWasmAllowed || is_string($this->jsNonce)) {
$policy .= 'script-src ';
- if (is_string($this->useJsNonce)) {
+ $scriptSrc = '';
+ if (is_string($this->jsNonce)) {
if ($this->strictDynamicAllowed) {
- $policy .= '\'strict-dynamic\' ';
+ $scriptSrc .= '\'strict-dynamic\' ';
}
- $policy .= '\'nonce-'.base64_encode($this->useJsNonce).'\'';
+ $scriptSrc .= '\'nonce-'.base64_encode($this->jsNonce).'\'';
$allowedScriptDomains = array_flip($this->allowedScriptDomains);
unset($allowedScriptDomains['\'self\'']);
$this->allowedScriptDomains = array_flip($allowedScriptDomains);
if (count($allowedScriptDomains) !== 0) {
- $policy .= ' ';
+ $scriptSrc .= ' ';
}
}
if (is_array($this->allowedScriptDomains)) {
- $policy .= implode(' ', $this->allowedScriptDomains);
+ $scriptSrc .= implode(' ', $this->allowedScriptDomains);
}
if ($this->evalScriptAllowed) {
- $policy .= ' \'unsafe-eval\'';
+ $scriptSrc .= ' \'unsafe-eval\'';
}
if ($this->evalWasmAllowed) {
- $policy .= ' \'wasm-unsafe-eval\'';
+ $scriptSrc .= ' \'wasm-unsafe-eval\'';
}
+ $policy .= $scriptSrc . ';';
+ }
+
+ // We only need to set this if 'strictDynamicAllowed' is not set because otherwise we can simply fall back to script-src
+ if ($this->strictDynamicAllowedOnScripts && is_string($this->jsNonce) && !$this->strictDynamicAllowed) {
+ $policy .= 'script-src-elem \'strict-dynamic\' ';
+ $policy .= $scriptSrc ?? '';
$policy .= ';';
}
diff --git a/lib/public/AppFramework/Http/ParameterOutOfRangeException.php b/lib/public/AppFramework/Http/ParameterOutOfRangeException.php
new file mode 100644
index 00000000000..22518d8eddf
--- /dev/null
+++ b/lib/public/AppFramework/Http/ParameterOutOfRangeException.php
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\AppFramework\Http;
+
+/**
+ * @since 29.0.0
+ */
+class ParameterOutOfRangeException extends \OutOfRangeException {
+ /**
+ * @since 29.0.0
+ */
+ public function __construct(
+ protected string $parameterName,
+ protected int $actualValue,
+ protected int $minValue,
+ protected int $maxValue,
+ ) {
+ parent::__construct(
+ sprintf(
+ 'Parameter %s must be between %d and %d',
+ $this->parameterName,
+ $this->minValue,
+ $this->maxValue,
+ )
+ );
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getParameterName(): string {
+ return $this->parameterName;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getActualValue(): int {
+ return $this->actualValue;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getMinValue(): int {
+ return $this->minValue;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getMaxValue(): int {
+ return $this->maxValue;
+ }
+}
diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php
index dd4f2c53418..d28f45f4c60 100644
--- a/lib/public/AppFramework/Http/Response.php
+++ b/lib/public/AppFramework/Http/Response.php
@@ -112,9 +112,8 @@ class Response {
*/
public function cacheFor(int $cacheSeconds, bool $public = false, bool $immutable = false) {
if ($cacheSeconds > 0) {
- $pragma = $public ? 'public' : 'private';
- $this->addHeader('Cache-Control', sprintf('%s, max-age=%s, %s', $pragma, $cacheSeconds, ($immutable ? 'immutable' : 'must-revalidate')));
- $this->addHeader('Pragma', $pragma);
+ $cacheStore = $public ? 'public' : 'private';
+ $this->addHeader('Cache-Control', sprintf('%s, max-age=%s, %s', $cacheStore, $cacheSeconds, ($immutable ? 'immutable' : 'must-revalidate')));
// Set expires header
$expires = new \DateTime();
@@ -125,7 +124,7 @@ class Response {
$this->addHeader('Expires', $expires->format(\DateTimeInterface::RFC2822));
} else {
$this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
- unset($this->headers['Expires'], $this->headers['Pragma']);
+ unset($this->headers['Expires']);
}
return $this;
diff --git a/lib/public/AppFramework/Http/TooManyRequestsResponse.php b/lib/public/AppFramework/Http/TooManyRequestsResponse.php
index 043ae0161e9..688fb6cc385 100644
--- a/lib/public/AppFramework/Http/TooManyRequestsResponse.php
+++ b/lib/public/AppFramework/Http/TooManyRequestsResponse.php
@@ -26,8 +26,8 @@ declare(strict_types=1);
*/
namespace OCP\AppFramework\Http;
-use OCP\Template;
use OCP\AppFramework\Http;
+use OCP\Template;
/**
* A generic 429 response showing an 404 error page as well to the end-user
diff --git a/lib/public/AppFramework/OCSController.php b/lib/public/AppFramework/OCSController.php
index 51c71ad4e64..e7dd817b0aa 100644
--- a/lib/public/AppFramework/OCSController.php
+++ b/lib/public/AppFramework/OCSController.php
@@ -36,9 +36,24 @@ use OCP\IRequest;
* @since 8.1.0
*/
abstract class OCSController extends ApiController {
+ /**
+ * @since 22.0.0
+ */
public const RESPOND_UNAUTHORISED = 997;
+
+ /**
+ * @since 22.0.0
+ */
public const RESPOND_SERVER_ERROR = 996;
+
+ /**
+ * @since 22.0.0
+ */
public const RESPOND_NOT_FOUND = 998;
+
+ /**
+ * @since 22.0.0
+ */
public const RESPOND_UNKNOWN_ERROR = 999;
/** @var int */
@@ -59,10 +74,10 @@ abstract class OCSController extends ApiController {
* @since 8.1.0
*/
public function __construct($appName,
- IRequest $request,
- $corsMethods = 'PUT, POST, GET, DELETE, PATCH',
- $corsAllowedHeaders = 'Authorization, Content-Type, Accept, OCS-APIRequest',
- $corsMaxAge = 1728000) {
+ IRequest $request,
+ $corsMethods = 'PUT, POST, GET, DELETE, PATCH',
+ $corsAllowedHeaders = 'Authorization, Content-Type, Accept, OCS-APIRequest',
+ $corsMaxAge = 1728000) {
parent::__construct($appName, $request, $corsMethods,
$corsAllowedHeaders, $corsMaxAge);
$this->registerResponder('json', function ($data) {
diff --git a/lib/public/AppFramework/PublicShareController.php b/lib/public/AppFramework/PublicShareController.php
index 52acbe841b4..cbcb9343198 100644
--- a/lib/public/AppFramework/PublicShareController.php
+++ b/lib/public/AppFramework/PublicShareController.php
@@ -53,8 +53,8 @@ abstract class PublicShareController extends Controller {
* @since 14.0.0
*/
public function __construct(string $appName,
- IRequest $request,
- ISession $session) {
+ IRequest $request,
+ ISession $session) {
parent::__construct($appName, $request);
$this->session = $session;
@@ -86,7 +86,7 @@ abstract class PublicShareController extends Controller {
*
* @since 14.0.0
*/
- abstract protected function getPasswordHash(): string;
+ abstract protected function getPasswordHash(): ?string;
/**
* Is the provided token a valid token
diff --git a/lib/public/AppFramework/Services/IAppConfig.php b/lib/public/AppFramework/Services/IAppConfig.php
index baac2946e3c..9340fdd3c32 100644
--- a/lib/public/AppFramework/Services/IAppConfig.php
+++ b/lib/public/AppFramework/Services/IAppConfig.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -25,6 +26,8 @@ declare(strict_types=1);
*/
namespace OCP\AppFramework\Services;
+use OCP\Exceptions\AppConfigUnknownKeyException;
+
/**
* Wrapper for AppConfig for the AppFramework
*
@@ -37,7 +40,58 @@ interface IAppConfig {
* @return string[] the keys stored for the app
* @since 20.0.0
*/
- public function getAppKeys(): array ;
+ public function getAppKeys(): array;
+
+ /**
+ * Check if a key exists in the list of stored config values.
+ *
+ * @param string $key config key
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return bool TRUE if key exists
+ * @since 29.0.0
+ */
+ public function hasAppKey(string $key, ?bool $lazy = false): bool;
+
+ /**
+ * best way to see if a value is set as sensitive (not displayed in report)
+ *
+ * @param string $key config key
+ * @param bool|null $lazy search within lazy loaded config
+ *
+ * @return bool TRUE if value is sensitive
+ * @throws AppConfigUnknownKeyException if config key is not known
+ * @since 29.0.0
+ */
+ public function isSensitive(string $key, ?bool $lazy = false): bool;
+
+ /**
+ * Returns if the config key stored in database is lazy loaded
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $key config key
+ *
+ * @return bool TRUE if config is lazy loaded
+ * @throws AppConfigUnknownKeyException if config key is not known
+ * @see IAppConfig for details about lazy loading
+ * @since 29.0.0
+ */
+ public function isLazy(string $key): bool;
+
+ /**
+ * List all config values from an app with config key starting with $key.
+ * Returns an array with config key as key, stored value as value.
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $key config keys prefix to search, can be empty.
+ * @param bool $filtered filter sensitive config values
+ *
+ * @return array<string, string> [configKey => configValue]
+ * @since 29.0.0
+ */
+ public function getAllAppValues(string $key = '', bool $filtered = false): array;
/**
* Writes a new app wide value
@@ -46,20 +100,197 @@ interface IAppConfig {
* @param string $value the value that should be stored
* @return void
* @since 20.0.0
+ * @deprecated 29.0.0 use {@see setAppValueString()}
*/
public function setAppValue(string $key, string $value): void;
/**
+ * Store a config key and its value in database
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $key config key
+ * @param string $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function setAppValueString(string $key, string $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * When handling huge value around and/or above 2,147,483,647, a debug log will be generated
+ * on 64bits system, as php int type reach its limit (and throw an exception) on 32bits when using huge numbers.
+ *
+ * When using huge numbers, it is advised to use {@see \OCP\Util::numericToNumber()} and {@see setValueString()}
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $key config key
+ * @param int $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function setAppValueInt(string $key, int $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * Store a config key and its value in database.
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $key config key
+ * @param float $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function setAppValueFloat(string $key, float $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $key config key
+ * @param bool $value config value
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function setAppValueBool(string $key, bool $value, bool $lazy = false): bool;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $key config key
+ * @param array $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function setAppValueArray(string $key, array $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
* Looks up an app wide defined value
*
* @param string $key the key of the value, under which it was saved
* @param string $default the default value to be returned if the value isn't set
+ *
* @return string the saved value
* @since 20.0.0
+ * @deprecated 29.0.0 use {@see getAppValueString()}
*/
public function getAppValue(string $key, string $default = ''): string;
/**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $key config key
+ * @param string $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return string stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function getAppValueString(string $key, string $default = '', bool $lazy = false): string;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $key config key
+ * @param int $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return int stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function getAppValueInt(string $key, int $default = 0, bool $lazy = false): int;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $key config key
+ * @param float $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return float stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function getAppValueFloat(string $key, float $default = 0, bool $lazy = false): float;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $key config key
+ * @param bool $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return bool stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function getAppValueBool(string $key, bool $default = false, bool $lazy = false): bool;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $key config key
+ * @param array $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return array stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see \OCP\IAppConfig for explanation about lazy loading
+ */
+ public function getAppValueArray(string $key, array $default = [], bool $lazy = false): array;
+
+ /**
* Delete an app wide defined value
*
* @param string $key the key of the value, under which it was saved
diff --git a/lib/public/AppFramework/Utility/ITimeFactory.php b/lib/public/AppFramework/Utility/ITimeFactory.php
index d4f74c9d107..be1b80ff617 100644
--- a/lib/public/AppFramework/Utility/ITimeFactory.php
+++ b/lib/public/AppFramework/Utility/ITimeFactory.php
@@ -33,7 +33,7 @@ use Psr\Clock\ClockInterface;
* Use this to get a timestamp or DateTime object in code to remain testable
*
* @since 8.0.0
- * @since 26.0.0 Extends the \Psr\Clock\ClockInterface interface
+ * @since 27.0.0 Extends the \Psr\Clock\ClockInterface interface
* @ref https://www.php-fig.org/psr/psr-20/#21-clockinterface
*/
@@ -58,4 +58,12 @@ interface ITimeFactory extends ClockInterface {
* @since 26.0.0
*/
public function withTimeZone(\DateTimeZone $timezone): static;
+
+ /**
+ * @param string|null $timezone
+ * @return \DateTimeZone Requested timezone if provided, UTC otherwise
+ * @throws \Exception
+ * @since 29.0.0
+ */
+ public function getTimeZone(?string $timezone = null): \DateTimeZone;
}
diff --git a/lib/public/Authentication/Exceptions/ExpiredTokenException.php b/lib/public/Authentication/Exceptions/ExpiredTokenException.php
new file mode 100644
index 00000000000..5c1f4a30541
--- /dev/null
+++ b/lib/public/Authentication/Exceptions/ExpiredTokenException.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Authentication\Exceptions;
+
+use OCP\Authentication\Token\IToken;
+
+/**
+ * @since 28.0.0
+ */
+class ExpiredTokenException extends InvalidTokenException {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IToken $token,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getToken(): IToken {
+ return $this->token;
+ }
+}
diff --git a/lib/public/Authentication/Exceptions/InvalidTokenException.php b/lib/public/Authentication/Exceptions/InvalidTokenException.php
new file mode 100644
index 00000000000..4869cbd6465
--- /dev/null
+++ b/lib/public/Authentication/Exceptions/InvalidTokenException.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ *
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Authentication\Exceptions;
+
+use Exception;
+
+/**
+ * @since 28.0.0
+ */
+class InvalidTokenException extends Exception {
+}
diff --git a/lib/public/Authentication/Exceptions/WipeTokenException.php b/lib/public/Authentication/Exceptions/WipeTokenException.php
new file mode 100644
index 00000000000..81ea2dc57ad
--- /dev/null
+++ b/lib/public/Authentication/Exceptions/WipeTokenException.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Authentication\Exceptions;
+
+use OCP\Authentication\Token\IToken;
+
+/**
+ * @since 28.0.0
+ */
+class WipeTokenException extends InvalidTokenException {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private IToken $token,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getToken(): IToken {
+ return $this->token;
+ }
+}
diff --git a/lib/public/Authentication/Token/IProvider.php b/lib/public/Authentication/Token/IProvider.php
index da2e400eb79..59d2b8f3649 100644
--- a/lib/public/Authentication/Token/IProvider.php
+++ b/lib/public/Authentication/Token/IProvider.php
@@ -24,6 +24,10 @@ declare(strict_types=1);
*/
namespace OCP\Authentication\Token;
+use OCP\Authentication\Exceptions\ExpiredTokenException;
+use OCP\Authentication\Exceptions\InvalidTokenException;
+use OCP\Authentication\Exceptions\WipeTokenException;
+
/**
* @since 24.0.8
*/
@@ -38,4 +42,15 @@ interface IProvider {
* @return void
*/
public function invalidateTokensOfUser(string $uid, ?string $clientName);
+
+ /**
+ * Get a token by token string id
+ *
+ * @since 28.0.0
+ * @throws InvalidTokenException
+ * @throws ExpiredTokenException
+ * @throws WipeTokenException
+ * @return IToken
+ */
+ public function getToken(string $tokenId): IToken;
}
diff --git a/lib/public/Authentication/Token/IToken.php b/lib/public/Authentication/Token/IToken.php
new file mode 100644
index 00000000000..7b6ce8327c6
--- /dev/null
+++ b/lib/public/Authentication/Token/IToken.php
@@ -0,0 +1,139 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ *
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCP\Authentication\Token;
+
+use JsonSerializable;
+
+/**
+ * @since 28.0.0
+ */
+interface IToken extends JsonSerializable {
+ /**
+ * @since 28.0.0
+ */
+ public const TEMPORARY_TOKEN = 0;
+ /**
+ * @since 28.0.0
+ */
+ public const PERMANENT_TOKEN = 1;
+ /**
+ * @since 28.0.0
+ */
+ public const WIPE_TOKEN = 2;
+ /**
+ * @since 28.0.0
+ */
+ public const DO_NOT_REMEMBER = 0;
+ /**
+ * @since 28.0.0
+ */
+ public const REMEMBER = 1;
+
+ /**
+ * Get the token ID
+ * @since 28.0.0
+ */
+ public function getId(): int;
+
+ /**
+ * Get the user UID
+ * @since 28.0.0
+ */
+ public function getUID(): string;
+
+ /**
+ * Get the login name used when generating the token
+ * @since 28.0.0
+ */
+ public function getLoginName(): string;
+
+ /**
+ * Get the (encrypted) login password
+ * @since 28.0.0
+ */
+ public function getPassword(): ?string;
+
+ /**
+ * Get the timestamp of the last password check
+ * @since 28.0.0
+ */
+ public function getLastCheck(): int;
+
+ /**
+ * Set the timestamp of the last password check
+ * @since 28.0.0
+ */
+ public function setLastCheck(int $time): void;
+
+ /**
+ * Get the authentication scope for this token
+ * @since 28.0.0
+ */
+ public function getScope(): string;
+
+ /**
+ * Get the authentication scope for this token
+ * @since 28.0.0
+ */
+ public function getScopeAsArray(): array;
+
+ /**
+ * Set the authentication scope for this token
+ * @since 28.0.0
+ */
+ public function setScope(array $scope): void;
+
+ /**
+ * Get the name of the token
+ * @since 28.0.0
+ */
+ public function getName(): string;
+
+ /**
+ * Get the remember state of the token
+ * @since 28.0.0
+ */
+ public function getRemember(): int;
+
+ /**
+ * Set the token
+ * @since 28.0.0
+ */
+ public function setToken(string $token): void;
+
+ /**
+ * Set the password
+ * @since 28.0.0
+ */
+ public function setPassword(string $password): void;
+
+ /**
+ * Set the expiration time of the token
+ * @since 28.0.0
+ */
+ public function setExpires(?int $expires): void;
+}
diff --git a/lib/public/Authentication/TwoFactorAuth/IRegistry.php b/lib/public/Authentication/TwoFactorAuth/IRegistry.php
index 0f164902f67..19010e5e5bf 100644
--- a/lib/public/Authentication/TwoFactorAuth/IRegistry.php
+++ b/lib/public/Authentication/TwoFactorAuth/IRegistry.php
@@ -39,11 +39,13 @@ use OCP\IUser;
*/
interface IRegistry {
/**
+ * @since 15.0.0
* @deprecated 22.0.0
*/
public const EVENT_PROVIDER_ENABLED = self::class . '::enable';
/**
+ * @since 15.0.0
* @deprecated 22.0.0
*/
public const EVENT_PROVIDER_DISABLED = self::class . '::disable';
diff --git a/lib/public/BackgroundJob/IJobList.php b/lib/public/BackgroundJob/IJobList.php
index 65e2f5b6250..07b5ebcf48b 100644
--- a/lib/public/BackgroundJob/IJobList.php
+++ b/lib/public/BackgroundJob/IJobList.php
@@ -32,8 +32,8 @@ namespace OCP\BackgroundJob;
* This interface provides functions to register background jobs
*
* To create a new background job create a new class that inherits from either
- * \OC\BackgroundJob\Job, \OC\BackgroundJob\QueuedJob or
- * \OC\BackgroundJob\TimedJob and register it using ->add($job, $argument),
+ * \OCP\BackgroundJob\Job, \OCP\BackgroundJob\QueuedJob or
+ * \OCP\BackgroundJob\TimedJob and register it using ->add($job, $argument),
* $argument will be passed to the run() function of the job when the job is
* executed.
*
@@ -58,6 +58,19 @@ interface IJobList {
public function add($job, $argument = null): void;
/**
+ * Add a job to the list but only run it after the given timestamp
+ *
+ * For cron background jobs this means the job will likely run shortly after the timestamp
+ * has been reached. For ajax background jobs the job might only run when users are active
+ * on the instance again.
+ *
+ * @param class-string<IJob> $job
+ * @param mixed $argument The serializable argument to be passed to $job->run() when the job is executed
+ * @since 28.0.0
+ */
+ public function scheduleAfter(string $job, int $runAfter, $argument = null): void;
+
+ /**
* Remove a job from the list
*
* @param IJob|class-string<IJob> $job
@@ -147,7 +160,8 @@ interface IJobList {
public function resetBackgroundJob(IJob $job): void;
/**
- * Checks whether a job of the passed class is reserved to run
+ * Checks whether a job of the passed class was reserved to run
+ * in the last 6h
*
* @param string|null $className
* @return bool
diff --git a/lib/public/BackgroundJob/Job.php b/lib/public/BackgroundJob/Job.php
index a574e90e1a0..3d1a117ac9e 100644
--- a/lib/public/BackgroundJob/Job.php
+++ b/lib/public/BackgroundJob/Job.php
@@ -44,7 +44,6 @@ abstract class Job implements IJob, IParallelAwareJob {
protected $argument;
protected ITimeFactory $time;
protected bool $allowParallelRuns = true;
- private ?ILogger $logger = null;
/**
* @since 15.0.0
@@ -56,14 +55,13 @@ abstract class Job implements IJob, IParallelAwareJob {
/**
* The function to prepare the execution of the job.
*
- *
- * @param IJobList $jobList
- * @param ILogger|null $logger
+ * @return void
*
* @since 15.0.0
+ * @deprecated since 25.0.0 Use start() instead. This method will be removed
+ * with the ILogger interface
*/
- public function execute(IJobList $jobList, ILogger $logger = null) {
- $this->logger = $logger;
+ public function execute(IJobList $jobList, ?ILogger $logger = null) {
$this->start($jobList);
}
@@ -73,19 +71,20 @@ abstract class Job implements IJob, IParallelAwareJob {
*/
public function start(IJobList $jobList): void {
$jobList->setLastRun($this);
- $logger = $this->logger ?? \OCP\Server::get(LoggerInterface::class);
+ $logger = \OCP\Server::get(LoggerInterface::class);
try {
+ $jobDetails = get_class($this) . ' (id: ' . $this->getId() . ', arguments: ' . json_encode($this->getArgument()) . ')';
$jobStartTime = $this->time->getTime();
- $logger->debug('Run ' . get_class($this) . ' job with ID ' . $this->getId(), ['app' => 'cron']);
+ $logger->debug('Starting job ' . $jobDetails, ['app' => 'cron']);
$this->run($this->argument);
$timeTaken = $this->time->getTime() - $jobStartTime;
- $logger->debug('Finished ' . get_class($this) . ' job with ID ' . $this->getId() . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']);
+ $logger->debug('Finished job ' . $jobDetails . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']);
$jobList->setExecutionTime($this, $timeTaken);
} catch (\Throwable $e) {
if ($logger) {
- $logger->error('Error while running background job (class: ' . get_class($this) . ', arguments: ' . print_r($this->argument, true) . ')', [
+ $logger->error('Error while running background job ' . $jobDetails, [
'app' => 'core',
'exception' => $e,
]);
@@ -158,6 +157,7 @@ abstract class Job implements IJob, IParallelAwareJob {
* The actual function that is called to run the job
*
* @param $argument
+ * @return void
*
* @since 15.0.0
*/
diff --git a/lib/public/Cache/CappedMemoryCache.php b/lib/public/Cache/CappedMemoryCache.php
index 6699600d42c..c92f68044ba 100644
--- a/lib/public/Cache/CappedMemoryCache.php
+++ b/lib/public/Cache/CappedMemoryCache.php
@@ -30,6 +30,7 @@ use OCP\ICache;
*
* @since 25.0.0
* @template T
+ * @template-implements \ArrayAccess<string,T>
*/
class CappedMemoryCache implements ICache, \ArrayAccess {
private int $capacity;
diff --git a/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php b/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php
index 5206dc37115..23879b93fa1 100644
--- a/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php
+++ b/lib/public/Collaboration/AutoComplete/AutoCompleteEvent.php
@@ -29,6 +29,7 @@ use OCP\EventDispatcher\GenericEvent;
/**
* @since 16.0.0
+ * @deprecated Use {@see AutoCompleteFilterEvent} instead
*/
class AutoCompleteEvent extends GenericEvent {
/**
diff --git a/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php b/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php
new file mode 100644
index 00000000000..fd1bec42abf
--- /dev/null
+++ b/lib/public/Collaboration/AutoComplete/AutoCompleteFilterEvent.php
@@ -0,0 +1,107 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Collaboration\AutoComplete;
+
+use OCP\EventDispatcher\Event;
+
+/**
+ * @since 28.0.0
+ */
+class AutoCompleteFilterEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected array $results,
+ protected string $search,
+ protected ?string $itemType,
+ protected ?string $itemId,
+ protected ?string $sorter,
+ protected array $shareTypes,
+ protected int $limit,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getResults(): array {
+ return $this->results;
+ }
+
+ /**
+ * @param array $results
+ * @since 28.0.0
+ */
+ public function setResults(array $results): void {
+ $this->results = $results;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getSearchTerm(): string {
+ return $this->search;
+ }
+
+ /**
+ * @return int[] List of `\OCP\Share\IShare::TYPE_*` constants
+ * @since 28.0.0
+ */
+ public function getShareTypes(): array {
+ return $this->shareTypes;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getItemType(): ?string {
+ return $this->itemType;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getItemId(): ?string {
+ return $this->itemId;
+ }
+
+ /**
+ * @return ?string List of desired sort identifiers, top priority first. When multiple are given they are joined with a pipe: `commenters|share-recipients`
+ * @since 28.0.0
+ */
+ public function getSorter(): ?string {
+ return $this->sorter;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getLimit(): int {
+ return $this->limit;
+ }
+}
diff --git a/lib/public/Collaboration/Reference/IReference.php b/lib/public/Collaboration/Reference/IReference.php
index 1b9157fd9b1..c0cfa72c36d 100644
--- a/lib/public/Collaboration/Reference/IReference.php
+++ b/lib/public/Collaboration/Reference/IReference.php
@@ -126,4 +126,11 @@ interface IReference extends JsonSerializable {
* @since 25.0.0
*/
public function getOpenGraphObject(): array;
+
+ /**
+ * @return array{richObjectType: string, richObject: array<string, mixed>, openGraphObject: array{id: string, name: string, description: ?string, thumb: ?string, link: string}, accessible: bool}
+ *
+ * @since 25.0.0
+ */
+ public function jsonSerialize(): array;
}
diff --git a/lib/public/Collaboration/Reference/LinkReferenceProvider.php b/lib/public/Collaboration/Reference/LinkReferenceProvider.php
new file mode 100644
index 00000000000..d41c1160c7c
--- /dev/null
+++ b/lib/public/Collaboration/Reference/LinkReferenceProvider.php
@@ -0,0 +1,221 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @author Anupam Kumar <kyteinsky@gmail.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Collaboration\Reference;
+
+use Fusonic\OpenGraph\Consumer;
+use GuzzleHttp\Exception\GuzzleException;
+use GuzzleHttp\Psr7\LimitStream;
+use GuzzleHttp\Psr7\Utils;
+use OC\Security\RateLimiting\Exception\RateLimitExceededException;
+use OC\Security\RateLimiting\Limiter;
+use OC\SystemConfig;
+use OCP\Files\AppData\IAppDataFactory;
+use OCP\Files\NotFoundException;
+use OCP\Http\Client\IClientService;
+use OCP\IRequest;
+use OCP\IURLGenerator;
+use OCP\IUserSession;
+use Psr\Log\LoggerInterface;
+
+/**
+ * @since 29.0.0
+ */
+class LinkReferenceProvider implements IReferenceProvider {
+
+ /**
+ * for image size and webpage header
+ * @since 29.0.0
+ */
+ public const MAX_CONTENT_LENGTH = 5 * 1024 * 1024;
+
+ /**
+ * @since 29.0.0
+ */
+ public const ALLOWED_CONTENT_TYPES = [
+ 'image/png',
+ 'image/jpg',
+ 'image/jpeg',
+ 'image/gif',
+ 'image/svg+xml',
+ 'image/webp'
+ ];
+
+ /**
+ * @since 29.0.0
+ */
+ public function __construct(
+ private IClientService $clientService,
+ private LoggerInterface $logger,
+ private SystemConfig $systemConfig,
+ private IAppDataFactory $appDataFactory,
+ private IURLGenerator $urlGenerator,
+ private Limiter $limiter,
+ private IUserSession $userSession,
+ private IRequest $request,
+ ) {
+ }
+
+ /**
+ * @inheritDoc
+ * @since 29.0.0
+ */
+ public function matchReference(string $referenceText): bool {
+ if ($this->systemConfig->getValue('reference_opengraph', true) !== true) {
+ return false;
+ }
+
+ return (bool)preg_match(IURLGenerator::URL_REGEX, $referenceText);
+ }
+
+ /**
+ * @inheritDoc
+ * @since 29.0.0
+ */
+ public function resolveReference(string $referenceText): ?IReference {
+ if ($this->matchReference($referenceText)) {
+ $reference = new Reference($referenceText);
+ $this->fetchReference($reference);
+ return $reference;
+ }
+
+ return null;
+ }
+
+ /**
+ * Populates the reference with OpenGraph data
+ *
+ * @param Reference $reference
+ * @since 29.0.0
+ */
+ private function fetchReference(Reference $reference): void {
+ try {
+ $user = $this->userSession->getUser();
+ if ($user) {
+ $this->limiter->registerUserRequest('opengraph', 10, 120, $user);
+ } else {
+ $this->limiter->registerAnonRequest('opengraph', 10, 120, $this->request->getRemoteAddress());
+ }
+ } catch (RateLimitExceededException $e) {
+ return;
+ }
+
+ $client = $this->clientService->newClient();
+ try {
+ $headResponse = $client->head($reference->getId(), [ 'timeout' => 10 ]);
+ } catch (\Exception $e) {
+ $this->logger->debug('Failed to perform HEAD request to get target metadata', ['exception' => $e]);
+ return;
+ }
+
+ $linkContentLength = $headResponse->getHeader('Content-Length');
+ if (is_numeric($linkContentLength) && (int) $linkContentLength > self::MAX_CONTENT_LENGTH) {
+ $this->logger->debug('Skip resolving links pointing to content length > 5 MiB');
+ return;
+ }
+
+ $linkContentType = $headResponse->getHeader('Content-Type');
+ $expectedContentTypeRegex = '/^text\/html;?/i';
+
+ // check the header begins with the expected content type
+ if (!preg_match($expectedContentTypeRegex, $linkContentType)) {
+ $this->logger->debug('Skip resolving links pointing to content type that is not "text/html"');
+ return;
+ }
+
+ try {
+ $response = $client->get($reference->getId(), [ 'timeout' => 10 ]);
+ } catch (\Exception $e) {
+ $this->logger->debug('Failed to fetch link for obtaining open graph data', ['exception' => $e]);
+ return;
+ }
+
+ $responseBody = (string)$response->getBody();
+
+ // OpenGraph handling
+ $consumer = new Consumer();
+ $consumer->useFallbackMode = true;
+ $object = $consumer->loadHtml($responseBody);
+
+ $reference->setUrl($reference->getId());
+
+ if ($object->title) {
+ $reference->setTitle($object->title);
+ }
+
+ if ($object->description) {
+ $reference->setDescription($object->description);
+ }
+
+ if ($object->images) {
+ try {
+ $host = parse_url($object->images[0]->url, PHP_URL_HOST);
+ if ($host === false || $host === null) {
+ $this->logger->warning('Could not detect host of open graph image URI for ' . $reference->getId());
+ return;
+ }
+
+ $appData = $this->appDataFactory->get('core');
+ try {
+ $folder = $appData->getFolder('opengraph');
+ } catch (NotFoundException $e) {
+ $folder = $appData->newFolder('opengraph');
+ }
+
+ $response = $client->get($object->images[0]->url, ['timeout' => 10]);
+ $contentType = $response->getHeader('Content-Type');
+ $contentLength = $response->getHeader('Content-Length');
+
+ if (in_array($contentType, self::ALLOWED_CONTENT_TYPES, true) && $contentLength < self::MAX_CONTENT_LENGTH) {
+ $stream = Utils::streamFor($response->getBody());
+ $bodyStream = new LimitStream($stream, self::MAX_CONTENT_LENGTH, 0);
+ $reference->setImageContentType($contentType);
+ $folder->newFile(md5($reference->getId()), $bodyStream->getContents());
+ $reference->setImageUrl($this->urlGenerator->linkToRouteAbsolute('core.Reference.preview', ['referenceId' => md5($reference->getId())]));
+ }
+ } catch (GuzzleException $e) {
+ $this->logger->info('Failed to fetch and store the open graph image for ' . $reference->getId(), ['exception' => $e]);
+ } catch (\Throwable $e) {
+ $this->logger->error('Failed to fetch and store the open graph image for ' . $reference->getId(), ['exception' => $e]);
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
+ * @since 29.0.0
+ */
+ public function getCachePrefix(string $referenceId): string {
+ return $referenceId;
+ }
+
+ /**
+ * @inheritDoc
+ * @since 29.0.0
+ */
+ public function getCacheKey(string $referenceId): ?string {
+ return null;
+ }
+}
diff --git a/lib/public/Collaboration/Reference/Reference.php b/lib/public/Collaboration/Reference/Reference.php
index 0dcb665713c..8dc88edbeac 100644
--- a/lib/public/Collaboration/Reference/Reference.php
+++ b/lib/public/Collaboration/Reference/Reference.php
@@ -242,7 +242,7 @@ class Reference implements IReference {
* @since 25.0.0
* @return array{richObjectType: string, richObject: array<string, mixed>, openGraphObject: OpenGraphObject, accessible: bool}
*/
- public function jsonSerialize() {
+ public function jsonSerialize(): array {
return [
'richObjectType' => $this->getRichObjectType(),
'richObject' => $this->getRichObject(),
diff --git a/lib/public/Comments/CommentsEntityEvent.php b/lib/public/Comments/CommentsEntityEvent.php
index 3336b80d6b5..fd43a5539ff 100644
--- a/lib/public/Comments/CommentsEntityEvent.php
+++ b/lib/public/Comments/CommentsEntityEvent.php
@@ -33,6 +33,7 @@ use OCP\EventDispatcher\Event;
*/
class CommentsEntityEvent extends Event {
/**
+ * @since 9.1.0
* @deprecated 22.0.0 - Listen to the typed event instead.
*/
public const EVENT_ENTITY = 'OCP\Comments\ICommentsManager::registerEntity';
diff --git a/lib/public/Comments/CommentsEvent.php b/lib/public/Comments/CommentsEvent.php
index 1793a1e3a86..b04b5c2e6f9 100644
--- a/lib/public/Comments/CommentsEvent.php
+++ b/lib/public/Comments/CommentsEvent.php
@@ -32,21 +32,25 @@ use OCP\EventDispatcher\Event;
*/
class CommentsEvent extends Event {
/**
+ * @since 11.0.0
* @deprecated 22.0.0
*/
public const EVENT_ADD = 'OCP\Comments\ICommentsManager::addComment';
/**
+ * @since 11.0.0
* @deprecated 22.0.0
*/
public const EVENT_PRE_UPDATE = 'OCP\Comments\ICommentsManager::preUpdateComment';
/**
+ * @since 11.0.0
* @deprecated 22.0.0
*/
public const EVENT_UPDATE = 'OCP\Comments\ICommentsManager::updateComment';
/**
+ * @since 11.0.0
* @deprecated 22.0.0
*/
public const EVENT_DELETE = 'OCP\Comments\ICommentsManager::deleteComment';
diff --git a/lib/public/Comments/IComment.php b/lib/public/Comments/IComment.php
index eb696fa5f06..8182bcd15d0 100644
--- a/lib/public/Comments/IComment.php
+++ b/lib/public/Comments/IComment.php
@@ -33,6 +33,9 @@ namespace OCP\Comments;
* @since 9.0.0
*/
interface IComment {
+ /**
+ * @since 9.0.0
+ */
public const MAX_MESSAGE_LENGTH = 1000;
/**
@@ -280,6 +283,25 @@ interface IComment {
public function setReferenceId(?string $referenceId): IComment;
/**
+ * Returns the metadata of the comment
+ *
+ * @return array|null
+ * @since 29.0.0
+ */
+ public function getMetaData(): ?array;
+
+ /**
+ * Sets (overwrites) the metadata of the comment
+ * Data as a json encoded array
+ *
+ * @param array|null $metaData
+ * @return IComment
+ * @throws \JsonException When the metadata can not be converted to a json encoded string
+ * @since 29.0.0
+ */
+ public function setMetaData(?array $metaData): IComment;
+
+ /**
* Returns the reactions array if exists
*
* The keys is the emoji of reaction and the value is the total.
diff --git a/lib/public/Comments/ICommentsManager.php b/lib/public/Comments/ICommentsManager.php
index 8d7ffd164b3..3d47be3d951 100644
--- a/lib/public/Comments/ICommentsManager.php
+++ b/lib/public/Comments/ICommentsManager.php
@@ -114,11 +114,11 @@ interface ICommentsManager {
* @since 9.0.0
*/
public function getForObject(
- $objectType,
- $objectId,
- $limit = 0,
- $offset = 0,
- \DateTime $notOlderThan = null
+ $objectType,
+ $objectId,
+ $limit = 0,
+ $offset = 0,
+ \DateTime $notOlderThan = null
);
/**
@@ -271,6 +271,7 @@ interface ICommentsManager {
* @param IUser $user
* @return array [$fileId => $unreadCount]
* @since 12.0.0
+ * @deprecated 29.0.0 use getNumberOfUnreadCommentsForObjects instead
*/
public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user);
diff --git a/lib/public/Console/ConsoleEvent.php b/lib/public/Console/ConsoleEvent.php
index 99f42d2895f..2ab2521527c 100644
--- a/lib/public/Console/ConsoleEvent.php
+++ b/lib/public/Console/ConsoleEvent.php
@@ -32,6 +32,7 @@ use OCP\EventDispatcher\Event;
*/
class ConsoleEvent extends Event {
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_RUN = 'OC\Console\Application::run';
diff --git a/lib/public/Constants.php b/lib/public/Constants.php
index 6a38190e167..8bae05b51e8 100644
--- a/lib/public/Constants.php
+++ b/lib/public/Constants.php
@@ -43,10 +43,30 @@ class Constants {
* @since 8.0.0
*/
public const PERMISSION_CREATE = 4;
+
+ /**
+ * @since 8.0.0
+ */
public const PERMISSION_READ = 1;
+
+ /**
+ * @since 8.0.0
+ */
public const PERMISSION_UPDATE = 2;
+
+ /**
+ * @since 8.0.0
+ */
public const PERMISSION_DELETE = 8;
+
+ /**
+ * @since 8.0.0
+ */
public const PERMISSION_SHARE = 16;
+
+ /**
+ * @since 8.0.0
+ */
public const PERMISSION_ALL = 31;
/**
diff --git a/lib/public/Contacts/ContactsMenu/IBulkProvider.php b/lib/public/Contacts/ContactsMenu/IBulkProvider.php
new file mode 100644
index 00000000000..43d727e2ec3
--- /dev/null
+++ b/lib/public/Contacts/ContactsMenu/IBulkProvider.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Contacts\ContactsMenu;
+
+/**
+ * Process contacts menu entries in bulk
+ *
+ * @since 28.0
+ */
+interface IBulkProvider {
+ /**
+ * @since 28.0
+ * @param list<IEntry> $entries
+ * @return void
+ */
+ public function process(array $entries): void;
+}
diff --git a/lib/public/Contacts/ContactsMenu/IEntry.php b/lib/public/Contacts/ContactsMenu/IEntry.php
index 9d78b0c8f57..1307e2c74f7 100644
--- a/lib/public/Contacts/ContactsMenu/IEntry.php
+++ b/lib/public/Contacts/ContactsMenu/IEntry.php
@@ -54,6 +54,20 @@ interface IEntry extends JsonSerializable {
public function addAction(IAction $action): void;
/**
+ * Set the (system) contact's user status
+ *
+ * @since 28.0
+ * @param string $status
+ * @param string $statusMessage
+ * @param string|null $icon
+ * @return void
+ */
+ public function setStatus(string $status,
+ string $statusMessage = null,
+ int $statusMessageTimestamp = null,
+ string $icon = null): void;
+
+ /**
* Get an arbitrary property from the contact
*
* @since 12.0
diff --git a/lib/public/Contacts/ContactsMenu/IProvider.php b/lib/public/Contacts/ContactsMenu/IProvider.php
index c05f2707c18..200ee0b1fea 100644
--- a/lib/public/Contacts/ContactsMenu/IProvider.php
+++ b/lib/public/Contacts/ContactsMenu/IProvider.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
*
@@ -23,6 +26,10 @@
namespace OCP\Contacts\ContactsMenu;
/**
+ * Process contacts menu entries
+ *
+ * @see IBulkProvider for providers that work with the full dataset at once
+ *
* @since 12.0
*/
interface IProvider {
diff --git a/lib/public/Contacts/IManager.php b/lib/public/Contacts/IManager.php
index 6ca349b95d0..97fa2e61529 100644
--- a/lib/public/Contacts/IManager.php
+++ b/lib/public/Contacts/IManager.php
@@ -107,22 +107,22 @@ interface IManager {
* This function can be used to delete the contact identified by the given id
*
* @param int $id the unique identifier to a contact
- * @param string $address_book_key identifier of the address book in which the contact shall be deleted
+ * @param string $addressBookKey identifier of the address book in which the contact shall be deleted
* @return bool successful or not
* @since 6.0.0
*/
- public function delete($id, $address_book_key);
+ public function delete($id, $addressBookKey);
/**
* This function is used to create a new contact if 'id' is not given or not present.
* Otherwise the contact will be updated by replacing the entire data set.
*
* @param array $properties this array if key-value-pairs defines a contact
- * @param string $address_book_key identifier of the address book in which the contact shall be created or updated
- * @return array an array representing the contact just created or updated
+ * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated
+ * @return ?array an array representing the contact just created or updated
* @since 6.0.0
*/
- public function createOrUpdate($properties, $address_book_key);
+ public function createOrUpdate($properties, $addressBookKey);
/**
* Check if contacts are available (e.g. contacts app enabled)
@@ -135,20 +135,19 @@ interface IManager {
/**
* Registers an address book
*
- * @param \OCP\IAddressBook $address_book
* @return void
* @since 6.0.0
*/
- public function registerAddressBook(\OCP\IAddressBook $address_book);
+ public function registerAddressBook(\OCP\IAddressBook $addressBook);
/**
* Unregisters an address book
*
- * @param \OCP\IAddressBook $address_book
+ * @param \OCP\IAddressBook $addressBook
* @return void
* @since 6.0.0
*/
- public function unregisterAddressBook(\OCP\IAddressBook $address_book);
+ public function unregisterAddressBook(\OCP\IAddressBook $addressBook);
/**
* In order to improve lazy loading a closure can be registered which will be called in case
diff --git a/lib/public/DB/Events/AddMissingIndicesEvent.php b/lib/public/DB/Events/AddMissingIndicesEvent.php
index dc942f3d63e..8b6d2a07a0c 100644
--- a/lib/public/DB/Events/AddMissingIndicesEvent.php
+++ b/lib/public/DB/Events/AddMissingIndicesEvent.php
@@ -39,6 +39,9 @@ class AddMissingIndicesEvent extends \OCP\EventDispatcher\Event {
/** @var array<array-key, array{tableName: string, indexName: string, columns: string[], options: array{}, dropUnnamedIndex: bool, uniqueIndex: bool}> */
private array $missingIndices = [];
+ /** @var array<array-key, array{tableName: string, oldIndexNames: array, newIndexName: string, columns: string[], uniqueIndex: bool, options: array{}}> */
+ private array $toReplaceIndices = [];
+
/**
* @param string[] $columns
* @since 28.0.0
@@ -75,4 +78,42 @@ class AddMissingIndicesEvent extends \OCP\EventDispatcher\Event {
public function getMissingIndices(): array {
return $this->missingIndices;
}
+
+ /**
+ * Replace one or more existing indices with a new one. Can be used to make an index unique afterwards or merge two indices into a multicolumn index.
+ *
+ * Note: Make sure to not use the same index name for the new index as for old indices.
+ *
+ * Example:
+ *
+ * <code>
+ * $event->replaceIndex(
+ * 'my_table',
+ * ['old_index_col_a', 'old_index_col_b'],
+ * 'new_index_col_a_b',
+ * ['column_a', 'column_b'],
+ * false
+ * );
+ * </code>
+ *
+ * @since 29.0.0
+ */
+ public function replaceIndex(string $tableName, array $oldIndexNames, string $newIndexName, array $columns, bool $unique, array $options = []): void {
+ $this->toReplaceIndices[] = [
+ 'tableName' => $tableName,
+ 'oldIndexNames' => $oldIndexNames,
+ 'newIndexName' => $newIndexName,
+ 'columns' => $columns,
+ 'uniqueIndex' => $unique,
+ 'options' => $options,
+ ];
+ }
+
+ /**
+ * @since 29.0.0
+ * @return array<array-key, array{tableName: string, oldIndexNames: array, newIndexName: string, columns: string[], uniqueIndex: bool, options: array{}}>
+ */
+ public function getIndicesToReplace(): array {
+ return $this->toReplaceIndices;
+ }
}
diff --git a/lib/public/DB/QueryBuilder/IQueryBuilder.php b/lib/public/DB/QueryBuilder/IQueryBuilder.php
index 63fdfb65971..dba5f390d6e 100644
--- a/lib/public/DB/QueryBuilder/IQueryBuilder.php
+++ b/lib/public/DB/QueryBuilder/IQueryBuilder.php
@@ -27,6 +27,7 @@
*/
namespace OCP\DB\QueryBuilder;
+use Doctrine\DBAL\ArrayParameterType;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;
use OCP\DB\Exception;
@@ -72,11 +73,11 @@ interface IQueryBuilder {
/**
* @since 9.0.0
*/
- public const PARAM_INT_ARRAY = Connection::PARAM_INT_ARRAY;
+ public const PARAM_INT_ARRAY = ArrayParameterType::INTEGER;
/**
* @since 9.0.0
*/
- public const PARAM_STR_ARRAY = Connection::PARAM_STR_ARRAY;
+ public const PARAM_STR_ARRAY = ArrayParameterType::STRING;
/**
* @since 24.0.0 Indicates how many rows can be deleted at once with MySQL
@@ -907,7 +908,7 @@ interface IQueryBuilder {
* @link http://www.zetacomponents.org
*
* @param mixed $value
- * @param mixed $type
+ * @param self::PARAM_* $type
* @param string $placeHolder The name to bind with. The string must start with a colon ':'.
*
* @return IParameter
@@ -935,7 +936,7 @@ interface IQueryBuilder {
* </code>
*
* @param mixed $value
- * @param integer $type
+ * @param self::PARAM_* $type
*
* @return IParameter
* @since 8.2.0
diff --git a/lib/public/Dashboard/IManager.php b/lib/public/Dashboard/IManager.php
index 77bff7b34ff..135fd4b4514 100644
--- a/lib/public/Dashboard/IManager.php
+++ b/lib/public/Dashboard/IManager.php
@@ -40,7 +40,7 @@ interface IManager {
/**
* @since 20.0.0
*
- * @return IWidget[]
+ * @return array<string, IWidget>
*/
public function getWidgets(): array;
}
diff --git a/lib/public/Dashboard/Model/WidgetButton.php b/lib/public/Dashboard/Model/WidgetButton.php
index 480249b539f..57ea06ec6b1 100644
--- a/lib/public/Dashboard/Model/WidgetButton.php
+++ b/lib/public/Dashboard/Model/WidgetButton.php
@@ -29,8 +29,19 @@ namespace OCP\Dashboard\Model;
* @since 25.0.0
*/
class WidgetButton {
+ /**
+ * @since 25.0.0
+ */
public const TYPE_NEW = 'new';
+
+ /**
+ * @since 25.0.0
+ */
public const TYPE_MORE = 'more';
+
+ /**
+ * @since 25.0.0
+ */
public const TYPE_SETUP = 'setup';
private string $type;
diff --git a/lib/public/Dashboard/Model/WidgetItem.php b/lib/public/Dashboard/Model/WidgetItem.php
index 1c54d2bd426..22235053b5d 100644
--- a/lib/public/Dashboard/Model/WidgetItem.php
+++ b/lib/public/Dashboard/Model/WidgetItem.php
@@ -70,11 +70,11 @@ final class WidgetItem implements JsonSerializable {
* @since 22.0.0
*/
public function __construct(string $title = '',
- string $subtitle = '',
- string $link = '',
- string $iconUrl = '',
- string $sinceId = '',
- string $overlayIconUrl = '') {
+ string $subtitle = '',
+ string $link = '',
+ string $iconUrl = '',
+ string $sinceId = '',
+ string $overlayIconUrl = '') {
$this->title = $title;
$this->subtitle = $subtitle;
$this->iconUrl = $iconUrl;
diff --git a/lib/public/EventDispatcher/IEventDispatcher.php b/lib/public/EventDispatcher/IEventDispatcher.php
index 0a96fa799d4..a84e0fe2f3b 100644
--- a/lib/public/EventDispatcher/IEventDispatcher.php
+++ b/lib/public/EventDispatcher/IEventDispatcher.php
@@ -71,6 +71,15 @@ interface IEventDispatcher {
/**
* @template T of \OCP\EventDispatcher\Event
+ * @param string $eventName preferably the fully-qualified class name of the Event sub class
+ *
+ * @return bool TRUE if event has registered listeners
+ * @since 29.0.0
+ */
+ public function hasListeners(string $eventName): bool;
+
+ /**
+ * @template T of \OCP\EventDispatcher\Event
* @param string $eventName
* @psalm-param string|class-string<T> $eventName
* @param Event $event
diff --git a/lib/public/Exceptions/AbortedEventException.php b/lib/public/Exceptions/AbortedEventException.php
new file mode 100644
index 00000000000..5a3b797e386
--- /dev/null
+++ b/lib/public/Exceptions/AbortedEventException.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Exceptions;
+
+use Exception;
+
+/**
+ * @since 29.0.0
+ */
+class AbortedEventException extends Exception {
+}
diff --git a/lib/public/Exceptions/AppConfigException.php b/lib/public/Exceptions/AppConfigException.php
new file mode 100644
index 00000000000..73c91d9f018
--- /dev/null
+++ b/lib/public/Exceptions/AppConfigException.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Exceptions;
+
+use Exception;
+
+/**
+ * @since 29.0.0
+ */
+class AppConfigException extends Exception {
+}
diff --git a/lib/public/Exceptions/AppConfigIncorrectTypeException.php b/lib/public/Exceptions/AppConfigIncorrectTypeException.php
new file mode 100644
index 00000000000..1284e4b193e
--- /dev/null
+++ b/lib/public/Exceptions/AppConfigIncorrectTypeException.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Exceptions;
+
+/**
+ * @since 29.0.0
+ */
+class AppConfigIncorrectTypeException extends AppConfigException {
+}
diff --git a/lib/public/Exceptions/AppConfigTypeConflictException.php b/lib/public/Exceptions/AppConfigTypeConflictException.php
new file mode 100644
index 00000000000..599fed0cb3b
--- /dev/null
+++ b/lib/public/Exceptions/AppConfigTypeConflictException.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Exceptions;
+
+/**
+ * @since 29.0.0
+ */
+class AppConfigTypeConflictException extends AppConfigException {
+}
diff --git a/lib/public/Exceptions/AppConfigUnknownKeyException.php b/lib/public/Exceptions/AppConfigUnknownKeyException.php
new file mode 100644
index 00000000000..e2b9d7fd3dc
--- /dev/null
+++ b/lib/public/Exceptions/AppConfigUnknownKeyException.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Exceptions;
+
+/**
+ * @since 29.0.0
+ */
+class AppConfigUnknownKeyException extends AppConfigException {
+}
diff --git a/lib/public/Federation/Exceptions/ActionNotSupportedException.php b/lib/public/Federation/Exceptions/ActionNotSupportedException.php
index e5f8d50fd99..a7dcda15fe5 100644
--- a/lib/public/Federation/Exceptions/ActionNotSupportedException.php
+++ b/lib/public/Federation/Exceptions/ActionNotSupportedException.php
@@ -38,7 +38,7 @@ class ActionNotSupportedException extends HintException {
*
*/
public function __construct($action) {
- $l = \OC::$server->getL10N('federation');
+ $l = \OCP\Util::getL10N('federation');
$message = 'Action "' . $action . '" not supported or implemented.';
$hint = $l->t('Action "%s" not supported or implemented.', [$action]);
parent::__construct($message, $hint);
diff --git a/lib/public/Federation/Exceptions/AuthenticationFailedException.php b/lib/public/Federation/Exceptions/AuthenticationFailedException.php
index 2bd3e361edd..63c8f63ab85 100644
--- a/lib/public/Federation/Exceptions/AuthenticationFailedException.php
+++ b/lib/public/Federation/Exceptions/AuthenticationFailedException.php
@@ -38,7 +38,7 @@ class AuthenticationFailedException extends HintException {
*
*/
public function __construct() {
- $l = \OC::$server->getL10N('federation');
+ $l = \OCP\Util::getL10N('federation');
$message = 'Authentication failed, wrong token or provider ID given';
$hint = $l->t('Authentication failed, wrong token or provider ID given');
parent::__construct($message, $hint);
diff --git a/lib/public/Federation/Exceptions/BadRequestException.php b/lib/public/Federation/Exceptions/BadRequestException.php
index bc8b5c7b724..fbd781aee43 100644
--- a/lib/public/Federation/Exceptions/BadRequestException.php
+++ b/lib/public/Federation/Exceptions/BadRequestException.php
@@ -45,7 +45,7 @@ class BadRequestException extends HintException {
* @param array $missingParameters
*/
public function __construct(array $missingParameters) {
- $l = \OC::$server->getL10N('federation');
+ $l = \OCP\Util::getL10N('federation');
$this->parameterList = $missingParameters;
$parameterList = implode(',', $missingParameters);
$message = 'Parameters missing in order to complete the request. Missing Parameters: ' . $parameterList;
diff --git a/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php b/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php
index d30d81eca27..cb0a8e8d51f 100644
--- a/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php
+++ b/lib/public/Federation/Exceptions/ProviderAlreadyExistsException.php
@@ -42,7 +42,7 @@ class ProviderAlreadyExistsException extends HintException {
* @param string $existingProviderName name of cloud federation provider which already use the same ID
*/
public function __construct($newProviderId, $existingProviderName) {
- $l = \OC::$server->getL10N('federation');
+ $l = \OCP\Util::getL10N('federation');
$message = 'ID "' . $newProviderId . '" already used by cloud federation provider "' . $existingProviderName . '"';
$hint = $l->t('ID "%1$s" already used by cloud federation provider "%2$s"', [$newProviderId, $existingProviderName]);
parent::__construct($message, $hint);
diff --git a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php
index 849209da22d..0594bb6875b 100644
--- a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php
+++ b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php
@@ -39,7 +39,7 @@ class ProviderDoesNotExistsException extends HintException {
* @param string $providerId cloud federation provider ID
*/
public function __construct($providerId) {
- $l = \OC::$server->getL10N('federation');
+ $l = \OCP\Util::getL10N('federation');
$message = 'Cloud Federation Provider with ID: "' . $providerId . '" does not exist.';
$hint = $l->t('Cloud Federation Provider with ID: "%s" does not exist.', [$providerId]);
parent::__construct($message, $hint);
diff --git a/lib/public/Federation/ICloudFederationNotification.php b/lib/public/Federation/ICloudFederationNotification.php
index 2b51b2bc8db..26a98027d5e 100644
--- a/lib/public/Federation/ICloudFederationNotification.php
+++ b/lib/public/Federation/ICloudFederationNotification.php
@@ -34,8 +34,8 @@ interface ICloudFederationNotification {
*
* @param string $notificationType (e.g. SHARE_ACCEPTED)
* @param string $resourceType (e.g. file, calendar, contact,...)
- * @param $providerId id of the share
- * @param array $notification , payload of the notification
+ * @param string $providerId id of the share
+ * @param array $notification payload of the notification
*
* @since 14.0.0
*/
diff --git a/lib/public/Federation/ICloudFederationProviderManager.php b/lib/public/Federation/ICloudFederationProviderManager.php
index 7272653b14d..14ac59f3b0b 100644
--- a/lib/public/Federation/ICloudFederationProviderManager.php
+++ b/lib/public/Federation/ICloudFederationProviderManager.php
@@ -23,6 +23,9 @@
*/
namespace OCP\Federation;
+use OCP\Http\Client\IResponse;
+use OCP\OCM\Exceptions\OCMProviderException;
+
/**
* Class ICloudFederationProviderManager
*
@@ -80,10 +83,19 @@ interface ICloudFederationProviderManager {
* @return mixed
*
* @since 14.0.0
+ * @deprecated 29.0.0 - Use {@see sendCloudShare()} instead and handle errors manually
*/
public function sendShare(ICloudFederationShare $share);
/**
+ * @param ICloudFederationShare $share
+ * @return IResponse
+ * @throws OCMProviderException
+ * @since 29.0.0
+ */
+ public function sendCloudShare(ICloudFederationShare $share): IResponse;
+
+ /**
* send notification about existing share
*
* @param string $url
@@ -91,10 +103,20 @@ interface ICloudFederationProviderManager {
* @return array|false
*
* @since 14.0.0
+ * @deprecated 29.0.0 - Use {@see sendCloudNotification()} instead and handle errors manually
*/
public function sendNotification($url, ICloudFederationNotification $notification);
/**
+ * @param string $url
+ * @param ICloudFederationNotification $notification
+ * @return IResponse
+ * @throws OCMProviderException
+ * @since 29.0.0
+ */
+ public function sendCloudNotification(string $url, ICloudFederationNotification $notification): IResponse;
+
+ /**
* check if the new cloud federation API is ready to be used
*
* @return bool
diff --git a/lib/public/Files/Cache/ICache.php b/lib/public/Files/Cache/ICache.php
index 1934cc24bd4..0a08673d6c3 100644
--- a/lib/public/Files/Cache/ICache.php
+++ b/lib/public/Files/Cache/ICache.php
@@ -38,9 +38,24 @@ use OCP\Files\Search\ISearchQuery;
* @since 9.0.0
*/
interface ICache {
+ /**
+ * @since 9.0.0
+ */
public const NOT_FOUND = 0;
+
+ /**
+ * @since 9.0.0
+ */
public const PARTIAL = 1; //only partial data available, file not cached in the database
+
+ /**
+ * @since 9.0.0
+ */
public const SHALLOW = 2; //folder in cache, but not all child files are completely scanned
+
+ /**
+ * @since 9.0.0
+ */
public const COMPLETE = 3;
/**
diff --git a/lib/public/Files/Cache/ICacheEntry.php b/lib/public/Files/Cache/ICacheEntry.php
index e1e8129394c..581d5aa6731 100644
--- a/lib/public/Files/Cache/ICacheEntry.php
+++ b/lib/public/Files/Cache/ICacheEntry.php
@@ -28,12 +28,16 @@ use ArrayAccess;
* meta data for a file or folder
*
* @since 9.0.0
+ * @template-extends ArrayAccess<string,mixed>
*
* This interface extends \ArrayAccess since v21.0.0, previous versions only
* implemented it in the private implementation. Hence php would allow using the
* object as array, while strictly speaking it didn't support this.
*/
interface ICacheEntry extends ArrayAccess {
+ /**
+ * @since 9.0.0
+ */
public const DIRECTORY_MIMETYPE = 'httpd/unix-directory';
/**
@@ -123,8 +127,8 @@ interface ICacheEntry extends ArrayAccess {
public function getEtag();
/**
- * Get the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE
- * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE
+ * Get the permissions for the file stored as bitwise combination of \OCP\Constants::PERMISSION_READ, \OCP\Constants::PERMISSION_CREATE
+ * \OCP\Constants::PERMISSION_UPDATE, \OCP\Constants::PERMISSION_DELETE and \OCP\Constants::PERMISSION_SHARE
*
* @return int
* @since 9.0.0
diff --git a/lib/public/Files/Cache/IScanner.php b/lib/public/Files/Cache/IScanner.php
index 8a45bfa6de7..e6ee4ef435f 100644
--- a/lib/public/Files/Cache/IScanner.php
+++ b/lib/public/Files/Cache/IScanner.php
@@ -28,12 +28,34 @@ namespace OCP\Files\Cache;
* @since 9.0.0
*/
interface IScanner {
+ /**
+ * @since 9.0.0
+ */
public const SCAN_RECURSIVE_INCOMPLETE = 2; // only recursive into not fully scanned folders
+
+ /**
+ * @since 9.0.0
+ */
public const SCAN_RECURSIVE = true;
+
+ /**
+ * @since 9.0.0
+ */
public const SCAN_SHALLOW = false;
+ /**
+ * @since 12.0.0
+ */
public const REUSE_NONE = 0;
+
+ /**
+ * @since 9.0.0
+ */
public const REUSE_ETAG = 1;
+
+ /**
+ * @since 9.0.0
+ */
public const REUSE_SIZE = 2;
/**
diff --git a/lib/public/Files/Cache/IUpdater.php b/lib/public/Files/Cache/IUpdater.php
index 5a776d4be7e..625bc91c5a7 100644
--- a/lib/public/Files/Cache/IUpdater.php
+++ b/lib/public/Files/Cache/IUpdater.php
@@ -53,7 +53,7 @@ interface IUpdater {
* @param int $time
* @since 9.0.0
*/
- public function update($path, $time = null);
+ public function update($path, $time = null, ?int $sizeDifference = null);
/**
* Remove $path from the cache and update the size, etag and mtime of the parent folders
diff --git a/lib/public/Files/Cache/IWatcher.php b/lib/public/Files/Cache/IWatcher.php
index f70024247d5..eca09507167 100644
--- a/lib/public/Files/Cache/IWatcher.php
+++ b/lib/public/Files/Cache/IWatcher.php
@@ -28,8 +28,19 @@ namespace OCP\Files\Cache;
* @since 9.0.0
*/
interface IWatcher {
+ /**
+ * @since 9.0.0
+ */
public const CHECK_NEVER = 0; // never check the underlying filesystem for updates
+
+ /**
+ * @since 9.0.0
+ */
public const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file
+
+ /**
+ * @since 9.0.0
+ */
public const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates
/**
diff --git a/lib/public/Files/Config/ICachedMountInfo.php b/lib/public/Files/Config/ICachedMountInfo.php
index dafd2423fdc..78a92874275 100644
--- a/lib/public/Files/Config/ICachedMountInfo.php
+++ b/lib/public/Files/Config/ICachedMountInfo.php
@@ -84,4 +84,12 @@ interface ICachedMountInfo {
* @since 24.0.0
*/
public function getMountProvider(): string;
+
+ /**
+ * Get a key that uniquely identifies the mount
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getKey(): string;
}
diff --git a/lib/public/Files/ConnectionLostException.php b/lib/public/Files/ConnectionLostException.php
new file mode 100644
index 00000000000..8e5deb99b46
--- /dev/null
+++ b/lib/public/Files/ConnectionLostException.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ *
+ * @author Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Files;
+
+/**
+ * Exception for lost connection with the
+ * @since 25.0.11
+ */
+class ConnectionLostException extends \RuntimeException {
+}
diff --git a/lib/public/Files/Events/FileCacheUpdated.php b/lib/public/Files/Events/FileCacheUpdated.php
index 18d6318f2f4..2669c51088e 100644
--- a/lib/public/Files/Events/FileCacheUpdated.php
+++ b/lib/public/Files/Events/FileCacheUpdated.php
@@ -44,7 +44,7 @@ class FileCacheUpdated extends Event {
* @since 18.0.0
*/
public function __construct(IStorage $storage,
- string $path) {
+ string $path) {
parent::__construct();
$this->storage = $storage;
$this->path = $path;
diff --git a/lib/public/Files/Events/Node/AbstractNodeEvent.php b/lib/public/Files/Events/Node/AbstractNodeEvent.php
index d6c1c6d0f95..768c0eda2d5 100644
--- a/lib/public/Files/Events/Node/AbstractNodeEvent.php
+++ b/lib/public/Files/Events/Node/AbstractNodeEvent.php
@@ -32,14 +32,12 @@ use OCP\Files\Node;
* @since 20.0.0
*/
abstract class AbstractNodeEvent extends Event {
- /** @var Node */
- private $node;
-
/**
* @since 20.0.0
*/
- public function __construct(Node $node) {
- $this->node = $node;
+ public function __construct(
+ private Node $node
+ ) {
}
/**
diff --git a/lib/public/Files/Events/Node/AbstractNodesEvent.php b/lib/public/Files/Events/Node/AbstractNodesEvent.php
index 6bd9bc32a88..d736ebf1635 100644
--- a/lib/public/Files/Events/Node/AbstractNodesEvent.php
+++ b/lib/public/Files/Events/Node/AbstractNodesEvent.php
@@ -32,17 +32,13 @@ use OCP\Files\Node;
* @since 20.0.0
*/
abstract class AbstractNodesEvent extends Event {
- /** @var Node */
- private $source;
- /** @var Node */
- private $target;
-
/**
* @since 20.0.0
*/
- public function __construct(Node $source, Node $target) {
- $this->source = $source;
- $this->target = $target;
+ public function __construct(
+ private Node $source,
+ private Node $target
+ ) {
}
/**
diff --git a/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php b/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php
index 316a30fadd8..c0226a9b527 100644
--- a/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php
+++ b/lib/public/Files/Events/Node/BeforeNodeDeletedEvent.php
@@ -25,8 +25,17 @@ declare(strict_types=1);
*/
namespace OCP\Files\Events\Node;
+use OCP\Exceptions\AbortedEventException;
+
/**
* @since 20.0.0
*/
class BeforeNodeDeletedEvent extends AbstractNodeEvent {
+ /**
+ * @since 28.0.0
+ * @deprecated 29.0.0 - use OCP\Exceptions\AbortedEventException instead
+ */
+ public function abortOperation(\Throwable $ex = null) {
+ throw new AbortedEventException($ex?->getMessage() ?? 'Operation aborted');
+ }
}
diff --git a/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php b/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php
index efbef03e383..4c2c566c8c6 100644
--- a/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php
+++ b/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php
@@ -25,8 +25,17 @@ declare(strict_types=1);
*/
namespace OCP\Files\Events\Node;
+use OCP\Exceptions\AbortedEventException;
+
/**
* @since 20.0.0
*/
class BeforeNodeRenamedEvent extends AbstractNodesEvent {
+ /**
+ * @since 28.0.0
+ * @deprecated 29.0.0 - use OCP\Exceptions\AbortedEventException instead
+ */
+ public function abortOperation(\Throwable $ex = null) {
+ throw new AbortedEventException($ex?->getMessage() ?? 'Operation aborted');
+ }
}
diff --git a/lib/public/Files/Events/NodeAddedToCache.php b/lib/public/Files/Events/NodeAddedToCache.php
index 6986b4b5989..3a1947e7a16 100644
--- a/lib/public/Files/Events/NodeAddedToCache.php
+++ b/lib/public/Files/Events/NodeAddedToCache.php
@@ -44,7 +44,7 @@ class NodeAddedToCache extends Event {
* @since 18.0.0
*/
public function __construct(IStorage $storage,
- string $path) {
+ string $path) {
parent::__construct();
$this->storage = $storage;
$this->path = $path;
diff --git a/lib/public/Files/Events/NodeRemovedFromCache.php b/lib/public/Files/Events/NodeRemovedFromCache.php
index 9f67cb71371..83c4bd16531 100644
--- a/lib/public/Files/Events/NodeRemovedFromCache.php
+++ b/lib/public/Files/Events/NodeRemovedFromCache.php
@@ -44,7 +44,7 @@ class NodeRemovedFromCache extends Event {
* @since 18.0.0
*/
public function __construct(IStorage $storage,
- string $path) {
+ string $path) {
parent::__construct();
$this->storage = $storage;
$this->path = $path;
diff --git a/lib/public/Files/FileInfo.php b/lib/public/Files/FileInfo.php
index 83ae4adef92..817b03dfc65 100644
--- a/lib/public/Files/FileInfo.php
+++ b/lib/public/Files/FileInfo.php
@@ -6,6 +6,7 @@
* @author Felix Heidecke <felix@heidecke.me>
* @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -299,4 +300,21 @@ interface FileInfo {
* @since 18.0.0
*/
public function getUploadTime(): int;
+
+ /**
+ * Get the fileid or the parent folder
+ * or -1 if this item has no parent folder (because it is the root)
+ *
+ * @return int
+ * @since 28.0.0
+ */
+ public function getParentId(): int;
+
+ /**
+ * Get the metadata, if available
+ *
+ * @return array<string, int|string|bool|float|string[]|int[]>
+ * @since 28.0.0
+ */
+ public function getMetadata(): array;
}
diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php
index eb81a2098ec..945df48a13e 100644
--- a/lib/public/Files/Folder.php
+++ b/lib/public/Files/Folder.php
@@ -152,11 +152,13 @@ interface Folder extends Node {
public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0);
/**
- * get a file or folder inside the folder by it's internal id
+ * get a file or folder inside the folder by its internal id
*
* This method could return multiple entries. For example once the file/folder
* is shared or mounted (files_external) to the user multiple times.
*
+ * Note that the different entries can have different permissions.
+ *
* @param int $id
* @return \OCP\Files\Node[]
* @since 6.0.0
@@ -164,6 +166,24 @@ interface Folder extends Node {
public function getById($id);
/**
+ * get a file or folder inside the folder by its internal id
+ *
+ * Unlike getById, this method only returns a single node even if the user has
+ * access to the file with the requested id multiple times.
+ *
+ * This method provides no guarantee about which of the nodes in returned and the
+ * returned node might, for example, have less permissions than other nodes for the same file
+ *
+ * Apps that require accurate information about the users access to the file should use getById
+ * instead of pick the correct node out of the result.
+ *
+ * @param int $id
+ * @return Node|null
+ * @since 29.0.0
+ */
+ public function getFirstNodeById(int $id): ?Node;
+
+ /**
* Get the amount of free space inside the folder
*
* @return int
diff --git a/lib/public/Files/IHomeStorage.php b/lib/public/Files/IHomeStorage.php
index 7eb3ffc4a24..1fea80f2d87 100644
--- a/lib/public/Files/IHomeStorage.php
+++ b/lib/public/Files/IHomeStorage.php
@@ -27,6 +27,7 @@
namespace OCP\Files;
use OCP\Files\Storage\IStorage;
+use OCP\IUser;
/**
* Interface IHomeStorage
@@ -34,4 +35,11 @@ use OCP\Files\Storage\IStorage;
* @since 7.0.0
*/
interface IHomeStorage extends IStorage {
+ /**
+ * Get the user for this home storage
+ *
+ * @return IUser
+ * @since 28.0.0
+ */
+ public function getUser(): IUser;
}
diff --git a/lib/public/Files/IMimeTypeLoader.php b/lib/public/Files/IMimeTypeLoader.php
index d4f2767bc17..39a5db85c1a 100644
--- a/lib/public/Files/IMimeTypeLoader.php
+++ b/lib/public/Files/IMimeTypeLoader.php
@@ -35,7 +35,7 @@ interface IMimeTypeLoader {
* @return string|null
* @since 8.2.0
*/
- public function getMimetypeById($id);
+ public function getMimetypeById(int $id): ?string;
/**
* Get a mimetype ID, adding the mimetype to the DB if it does not exist
@@ -44,7 +44,7 @@ interface IMimeTypeLoader {
* @return int
* @since 8.2.0
*/
- public function getId($mimetype);
+ public function getId(string $mimetype): int;
/**
* Test if a mimetype exists in the database
@@ -53,12 +53,12 @@ interface IMimeTypeLoader {
* @return bool
* @since 8.2.0
*/
- public function exists($mimetype);
+ public function exists(string $mimetype): bool;
/**
* Clear all loaded mimetypes, allow for re-loading
*
* @since 8.2.0
*/
- public function reset();
+ public function reset(): void;
}
diff --git a/lib/public/Files/IRootFolder.php b/lib/public/Files/IRootFolder.php
index 1fee0b3595e..c1c0e6e8c72 100644
--- a/lib/public/Files/IRootFolder.php
+++ b/lib/public/Files/IRootFolder.php
@@ -26,7 +26,9 @@ namespace OCP\Files;
use OC\Hooks\Emitter;
use OC\User\NoUserException;
+use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Mount\IMountPoint;
+use OCP\Files\Node as INode;
/**
* Interface IRootFolder
@@ -58,6 +60,24 @@ interface IRootFolder extends Folder, Emitter {
public function getByIdInPath(int $id, string $path);
/**
+ * get a file or folder inside the folder by its internal id
+ *
+ * Unlike getByIdInPath, this method only returns a single node even if the user has
+ * access to the file with the requested id multiple times.
+ *
+ * This method provides no guarantee about which of the nodes in returned and the
+ * returned node might, for example, have less permissions than other nodes for the same file
+ *
+ * Apps that require accurate information about the users access to the file should use getByIdInPath
+ * instead of pick the correct node out of the result.
+ *
+ * @param int $id
+ * @return Node|null
+ * @since 29.0.0
+ */
+ public function getFirstNodeByIdInPath(int $id, string $path): ?Node;
+
+ /**
* @return IMountPoint[]
*
* @since 28.0.0
@@ -65,6 +85,16 @@ interface IRootFolder extends Folder, Emitter {
public function getMountsIn(string $mountPoint): array;
/**
+ * Create a `Node` for a file or folder from the cache entry and mountpoint
+ *
+ * @param ICacheEntry $cacheEntry
+ * @param IMountPoint $mountPoint
+ * @return Node
+ * @since 28.0.0
+ */
+ public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode;
+
+ /**
* @since 28.0.0
*/
public function getMount(string $mountPoint): IMountPoint;
diff --git a/lib/public/Files/LockNotAcquiredException.php b/lib/public/Files/LockNotAcquiredException.php
index 4a26878cedf..2cf8ea20acf 100644
--- a/lib/public/Files/LockNotAcquiredException.php
+++ b/lib/public/Files/LockNotAcquiredException.php
@@ -43,7 +43,7 @@ class LockNotAcquiredException extends \Exception {
* @since 7.0.0
*/
public function __construct($path, $lockType, $code = 0, \Exception $previous = null) {
- $message = \OC::$server->getL10N('core')->t('Could not obtain lock type %d on "%s".', [$lockType, $path]);
+ $message = \OCP\Util::getL10N('core')->t('Could not obtain lock type %d on "%s".', [$lockType, $path]);
parent::__construct($message, $code, $previous);
}
diff --git a/lib/public/Files/Mount/IMountManager.php b/lib/public/Files/Mount/IMountManager.php
index a55e5758199..df2cc4c6209 100644
--- a/lib/public/Files/Mount/IMountManager.php
+++ b/lib/public/Files/Mount/IMountManager.php
@@ -26,6 +26,8 @@ declare(strict_types=1);
*/
namespace OCP\Files\Mount;
+use OCP\Files\Config\ICachedMountInfo;
+
/**
* Interface IMountManager
*
@@ -106,4 +108,14 @@ interface IMountManager {
* @since 8.2.0
*/
public function findByNumericId(int $id): array;
+
+ /**
+ * Return the mount matching a cached mount info (or mount file info)
+ *
+ * @param ICachedMountInfo $info
+ *
+ * @return IMountPoint|null
+ * @since 28.0.0
+ */
+ public function getMountFromMountInfo(ICachedMountInfo $info): ?IMountPoint;
}
diff --git a/lib/public/Files/Node.php b/lib/public/Files/Node.php
index b49b4a0f83d..ecf1427fa1a 100644
--- a/lib/public/Files/Node.php
+++ b/lib/public/Files/Node.php
@@ -30,8 +30,8 @@
namespace OCP\Files;
-use OCP\Lock\LockedException;
use OCP\Files\Storage\IStorage;
+use OCP\Lock\LockedException;
/**
* Interface Node
diff --git a/lib/public/Files/Notify/IChange.php b/lib/public/Files/Notify/IChange.php
index 2a4f806be46..d8fd61b1a47 100644
--- a/lib/public/Files/Notify/IChange.php
+++ b/lib/public/Files/Notify/IChange.php
@@ -29,9 +29,24 @@ namespace OCP\Files\Notify;
* @since 12.0.0
*/
interface IChange {
+ /**
+ * @since 12.0.0
+ */
public const ADDED = 1;
+
+ /**
+ * @since 12.0.0
+ */
public const REMOVED = 2;
+
+ /**
+ * @since 12.0.0
+ */
public const MODIFIED = 3;
+
+ /**
+ * @since 12.0.0
+ */
public const RENAMED = 4;
/**
diff --git a/lib/public/Files/Search/ISearchBinaryOperator.php b/lib/public/Files/Search/ISearchBinaryOperator.php
index 4b3bbfd21fc..6e088fd4c2c 100644
--- a/lib/public/Files/Search/ISearchBinaryOperator.php
+++ b/lib/public/Files/Search/ISearchBinaryOperator.php
@@ -27,8 +27,19 @@ namespace OCP\Files\Search;
* @since 12.0.0
*/
interface ISearchBinaryOperator extends ISearchOperator {
+ /**
+ * @since 12.0.0
+ */
public const OPERATOR_AND = 'and';
+
+ /**
+ * @since 12.0.0
+ */
public const OPERATOR_OR = 'or';
+
+ /**
+ * @since 12.0.0
+ */
public const OPERATOR_NOT = 'not';
/**
diff --git a/lib/public/Files/Search/ISearchComparison.php b/lib/public/Files/Search/ISearchComparison.php
index 8ebaeced304..eb93ef70bf6 100644
--- a/lib/public/Files/Search/ISearchComparison.php
+++ b/lib/public/Files/Search/ISearchComparison.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -25,16 +26,59 @@ namespace OCP\Files\Search;
/**
* @since 12.0.0
+ *
+ * @psalm-type ParamSingleValue = \DateTime|int|string|bool
+ * @psalm-type ParamValue = ParamSingleValue|list<ParamSingleValue>
*/
interface ISearchComparison extends ISearchOperator {
+ /**
+ * @since 12.0.0
+ */
public const COMPARE_EQUAL = 'eq';
+
+ /**
+ * @since 12.0.0
+ */
public const COMPARE_GREATER_THAN = 'gt';
+
+ /**
+ * @since 12.0.0
+ */
public const COMPARE_GREATER_THAN_EQUAL = 'gte';
+
+ /**
+ * @since 12.0.0
+ */
public const COMPARE_LESS_THAN = 'lt';
+
+ /**
+ * @since 12.0.0
+ */
public const COMPARE_LESS_THAN_EQUAL = 'lte';
+
+ /**
+ * @since 12.0.0
+ */
public const COMPARE_LIKE = 'like';
+
+ /**
+ * @since 23.0.0
+ */
public const COMPARE_LIKE_CASE_SENSITIVE = 'clike';
+ /**
+ * @since 28.0.0
+ */
+ public const COMPARE_DEFINED = 'is-defined';
+
+ /**
+ * @since 29.0.0
+ */
+ public const COMPARE_IN = 'in';
+
+ /**
+ * @since 23.0.0
+ */
public const HINT_PATH_EQ_HASH = 'path_eq_hash'; // transform `path = "$path"` into `path_hash = md5("$path")`, on by default
/**
@@ -43,7 +87,7 @@ interface ISearchComparison extends ISearchOperator {
* @return string
* @since 12.0.0
*/
- public function getType();
+ public function getType(): string;
/**
* Get the name of the field to compare with
@@ -53,13 +97,21 @@ interface ISearchComparison extends ISearchOperator {
* @return string
* @since 12.0.0
*/
- public function getField();
+ public function getField(): string;
+
+ /**
+ * extra means data are not related to the main files table
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getExtra(): string;
/**
* Get the value to compare the field with
*
- * @return string|integer|\DateTime
+ * @return ParamValue
* @since 12.0.0
*/
- public function getValue();
+ public function getValue(): string|int|bool|\DateTime|array;
}
diff --git a/lib/public/Files/Search/ISearchOrder.php b/lib/public/Files/Search/ISearchOrder.php
index 3b9e6e6713a..978668907ad 100644
--- a/lib/public/Files/Search/ISearchOrder.php
+++ b/lib/public/Files/Search/ISearchOrder.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -29,7 +30,14 @@ use OCP\Files\FileInfo;
* @since 12.0.0
*/
interface ISearchOrder {
+ /**
+ * @since 12.0.0
+ */
public const DIRECTION_ASCENDING = 'asc';
+
+ /**
+ * @since 12.0.0
+ */
public const DIRECTION_DESCENDING = 'desc';
/**
@@ -38,7 +46,7 @@ interface ISearchOrder {
* @return string
* @since 12.0.0
*/
- public function getDirection();
+ public function getDirection(): string;
/**
* The field to sort on
@@ -46,7 +54,15 @@ interface ISearchOrder {
* @return string
* @since 12.0.0
*/
- public function getField();
+ public function getField(): string;
+
+ /**
+ * extra means data are not related to the main files table
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getExtra(): string;
/**
* Apply the sorting on 2 FileInfo objects
diff --git a/lib/public/Files/Storage/INotifyStorage.php b/lib/public/Files/Storage/INotifyStorage.php
index 18bcf3c6adc..6b1dacc564a 100644
--- a/lib/public/Files/Storage/INotifyStorage.php
+++ b/lib/public/Files/Storage/INotifyStorage.php
@@ -31,9 +31,24 @@ use OCP\Files\Notify\INotifyHandler;
* @since 9.1.0
*/
interface INotifyStorage {
+ /**
+ * @since 9.1.0
+ */
public const NOTIFY_ADDED = 1;
+
+ /**
+ * @since 9.1.0
+ */
public const NOTIFY_REMOVED = 2;
+
+ /**
+ * @since 9.1.0
+ */
public const NOTIFY_MODIFIED = 3;
+
+ /**
+ * @since 9.1.0
+ */
public const NOTIFY_RENAMED = 4;
/**
diff --git a/lib/public/Files/StorageAuthException.php b/lib/public/Files/StorageAuthException.php
index 5fce191b57e..bc39f8e27f5 100644
--- a/lib/public/Files/StorageAuthException.php
+++ b/lib/public/Files/StorageAuthException.php
@@ -36,7 +36,7 @@ class StorageAuthException extends StorageNotAvailableException {
* @since 9.0.0
*/
public function __construct($message = '', \Exception $previous = null) {
- $l = \OC::$server->getL10N('core');
+ $l = \OCP\Util::getL10N('core');
parent::__construct($l->t('Storage unauthorized. %s', [$message]), self::STATUS_UNAUTHORIZED, $previous);
}
}
diff --git a/lib/public/Files/StorageBadConfigException.php b/lib/public/Files/StorageBadConfigException.php
index 0e16a24daa8..36d7329d4b5 100644
--- a/lib/public/Files/StorageBadConfigException.php
+++ b/lib/public/Files/StorageBadConfigException.php
@@ -36,7 +36,7 @@ class StorageBadConfigException extends StorageNotAvailableException {
* @since 9.0.0
*/
public function __construct($message = '', \Exception $previous = null) {
- $l = \OC::$server->getL10N('core');
+ $l = \OCP\Util::getL10N('core');
parent::__construct($l->t('Storage incomplete configuration. %s', [$message]), self::STATUS_INCOMPLETE_CONF, $previous);
}
}
diff --git a/lib/public/Files/StorageConnectionException.php b/lib/public/Files/StorageConnectionException.php
index 9113faf72a1..d29398172e6 100644
--- a/lib/public/Files/StorageConnectionException.php
+++ b/lib/public/Files/StorageConnectionException.php
@@ -36,7 +36,7 @@ class StorageConnectionException extends StorageNotAvailableException {
* @since 9.0.0
*/
public function __construct($message = '', \Exception $previous = null) {
- $l = \OC::$server->getL10N('core');
+ $l = \OCP\Util::getL10N('core');
parent::__construct($l->t('Storage connection error. %s', [$message]), self::STATUS_NETWORK_ERROR, $previous);
}
}
diff --git a/lib/public/Files/StorageNotAvailableException.php b/lib/public/Files/StorageNotAvailableException.php
index f600ef80808..78b004f8518 100644
--- a/lib/public/Files/StorageNotAvailableException.php
+++ b/lib/public/Files/StorageNotAvailableException.php
@@ -36,15 +36,43 @@ use OCP\HintException;
/**
* Storage is temporarily not available
- * @since 6.0.0 - since 8.2.1 based on HintException
+ * @since 6.0.0
+ * @since 8.2.1 based on HintException
*/
class StorageNotAvailableException extends HintException {
+ /**
+ * @since 8.2.0
+ */
public const STATUS_SUCCESS = 0;
+
+ /**
+ * @since 8.2.0
+ */
public const STATUS_ERROR = 1;
+
+ /**
+ * @since 8.2.0
+ */
public const STATUS_INDETERMINATE = 2;
+
+ /**
+ * @since 8.2.0
+ */
public const STATUS_INCOMPLETE_CONF = 3;
+
+ /**
+ * @since 8.2.0
+ */
public const STATUS_UNAUTHORIZED = 4;
+
+ /**
+ * @since 8.2.0
+ */
public const STATUS_TIMEOUT = 5;
+
+ /**
+ * @since 8.2.0
+ */
public const STATUS_NETWORK_ERROR = 6;
/**
@@ -56,7 +84,7 @@ class StorageNotAvailableException extends HintException {
* @since 6.0.0
*/
public function __construct($message = '', $code = self::STATUS_ERROR, \Exception $previous = null) {
- $l = \OC::$server->getL10N('core');
+ $l = \OCP\Util::getL10N('core');
parent::__construct($message, $l->t('Storage is temporarily not available'), $code, $previous);
}
diff --git a/lib/public/Files/StorageTimeoutException.php b/lib/public/Files/StorageTimeoutException.php
index bad88ad35e0..c20711d4181 100644
--- a/lib/public/Files/StorageTimeoutException.php
+++ b/lib/public/Files/StorageTimeoutException.php
@@ -36,7 +36,7 @@ class StorageTimeoutException extends StorageNotAvailableException {
* @since 9.0.0
*/
public function __construct($message = '', \Exception $previous = null) {
- $l = \OC::$server->getL10N('core');
+ $l = \OCP\Util::getL10N('core');
parent::__construct($l->t('Storage connection timeout. %s', [$message]), self::STATUS_TIMEOUT, $previous);
}
}
diff --git a/lib/public/Files/Template/TemplateFileCreator.php b/lib/public/Files/Template/TemplateFileCreator.php
index 43e96b6f21b..0c2f7a115a2 100644
--- a/lib/public/Files/Template/TemplateFileCreator.php
+++ b/lib/public/Files/Template/TemplateFileCreator.php
@@ -42,6 +42,7 @@ final class TemplateFileCreator implements \JsonSerializable {
protected $order = 100;
/**
* @since 27.0.0
+ * @deprecated 28.0.0
*/
protected string $actionLabel = '';
diff --git a/lib/public/FilesMetadata/AMetadataEvent.php b/lib/public/FilesMetadata/AMetadataEvent.php
new file mode 100644
index 00000000000..8cb8ea8d1b8
--- /dev/null
+++ b/lib/public/FilesMetadata/AMetadataEvent.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata;
+
+use OCP\EventDispatcher\Event;
+use OCP\Files\Node;
+use OCP\FilesMetadata\Model\IFilesMetadata;
+
+/**
+ * @since 28.0.0
+ */
+abstract class AMetadataEvent extends Event {
+ /**
+ * @param Node $node
+ * @param IFilesMetadata $metadata
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected Node $node,
+ protected IFilesMetadata $metadata
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * returns related node
+ *
+ * @return Node
+ * @since 28.0.0
+ */
+ public function getNode(): Node {
+ return $this->node;
+ }
+
+ /**
+ * returns metadata. if known, it already contains data from the database.
+ * If the object is modified using its setters, changes are stored in database at the end of the event.
+ *
+ * @return IFilesMetadata
+ * @since 28.0.0
+ */
+ public function getMetadata(): IFilesMetadata {
+ return $this->metadata;
+ }
+}
diff --git a/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php b/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php
new file mode 100644
index 00000000000..3d175994c32
--- /dev/null
+++ b/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Event;
+
+use OCP\FilesMetadata\AMetadataEvent;
+
+/**
+ * MetadataBackgroundEvent is an event similar to MetadataLiveEvent but dispatched
+ * on a background thread instead of live thread. Meaning there is no limit to
+ * the time required for the generation of your metadata.
+ *
+ * @see AMetadataEvent::getMetadata()
+ * @see AMetadataEvent::getNode()
+ * @since 28.0.0
+ */
+class MetadataBackgroundEvent extends AMetadataEvent {
+}
diff --git a/lib/public/FilesMetadata/Event/MetadataLiveEvent.php b/lib/public/FilesMetadata/Event/MetadataLiveEvent.php
new file mode 100644
index 00000000000..a89692fde92
--- /dev/null
+++ b/lib/public/FilesMetadata/Event/MetadataLiveEvent.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Event;
+
+use OCP\FilesMetadata\AMetadataEvent;
+
+/**
+ * MetadataLiveEvent is an event initiated when a file is created or updated.
+ * The app contains the Node related to the created/updated file, and a FilesMetadata that already
+ * contains the currently known metadata.
+ *
+ * Setting new metadata, or modifying already existing metadata with different value, will trigger
+ * the save of the metadata in the database.
+ *
+ * @see AMetadataEvent::getMetadata()
+ * @see AMetadataEvent::getNode()
+ * @see MetadataLiveEvent::requestBackgroundJob()
+ * @since 28.0.0
+ */
+class MetadataLiveEvent extends AMetadataEvent {
+ private bool $runAsBackgroundJob = false;
+
+ /**
+ * For heavy process, call this method if your app prefers to update metadata on a
+ * background/cron job, instead of the live process.
+ * A similar MetadataBackgroundEvent will be broadcast on next cron tick.
+ *
+ * @return void
+ * @since 28.0.0
+ */
+ public function requestBackgroundJob(): void {
+ $this->runAsBackgroundJob = true;
+ }
+
+ /**
+ * return true if any app that catch this event requested a re-run as background job
+ *
+ * @return bool
+ * @since 28.0.0
+ */
+ public function isRunAsBackgroundJobRequested(): bool {
+ return $this->runAsBackgroundJob;
+ }
+}
diff --git a/lib/public/FilesMetadata/Event/MetadataNamedEvent.php b/lib/public/FilesMetadata/Event/MetadataNamedEvent.php
new file mode 100644
index 00000000000..f8cfcf9bd01
--- /dev/null
+++ b/lib/public/FilesMetadata/Event/MetadataNamedEvent.php
@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Event;
+
+use OCP\Files\Node;
+use OCP\FilesMetadata\AMetadataEvent;
+use OCP\FilesMetadata\Model\IFilesMetadata;
+
+/**
+ * MetadataNamedEvent is an event similar to MetadataBackgroundEvent completed with a target name,
+ * used to limit the refresh of metadata only listeners capable of filtering themselves out.
+ *
+ * Meaning that when using this event, your app must implement a filter on the event's registered
+ * name returned by getName()
+ *
+ * This event is mostly triggered when a registered name is added to the files scan
+ * i.e. ./occ files:scan --generate-metadata [name]
+ *
+ * @see AMetadataEvent::getMetadata()
+ * @see AMetadataEvent::getNode()
+ * @see MetadataNamedEvent::getName()
+ * @since 28.0.0
+ */
+class MetadataNamedEvent extends AMetadataEvent {
+ /**
+ * @param Node $node
+ * @param IFilesMetadata $metadata
+ * @param string $name name assigned to the event
+ *
+ * @since 28.0.0
+ */
+ public function __construct(
+ Node $node,
+ IFilesMetadata $metadata,
+ private string $name = ''
+ ) {
+ parent::__construct($node, $metadata);
+ }
+
+ /**
+ * get the assigned name for the event.
+ * This is used to know if your app is the called one when running the
+ * ./occ files:scan --generate-metadata [name]
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getName(): string {
+ return $this->name;
+ }
+}
diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php
new file mode 100644
index 00000000000..e3f75a7a7af
--- /dev/null
+++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Exceptions;
+
+use Exception;
+
+/**
+ * @since 28.0.0
+ */
+class FilesMetadataException extends Exception {
+}
diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php
new file mode 100644
index 00000000000..0083e985a5e
--- /dev/null
+++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataKeyFormatException.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Exceptions;
+
+/**
+ * @since 28.0.0
+ */
+class FilesMetadataKeyFormatException extends FilesMetadataException {
+}
diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php
new file mode 100644
index 00000000000..9c03c5ba370
--- /dev/null
+++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Exceptions;
+
+/**
+ * @since 28.0.0
+ */
+class FilesMetadataNotFoundException extends FilesMetadataException {
+}
diff --git a/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php b/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php
new file mode 100644
index 00000000000..1d134c67ecf
--- /dev/null
+++ b/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Exceptions;
+
+/**
+ * @since 28.0.0
+ */
+class FilesMetadataTypeException extends FilesMetadataException {
+}
diff --git a/lib/public/FilesMetadata/IFilesMetadataManager.php b/lib/public/FilesMetadata/IFilesMetadataManager.php
new file mode 100644
index 00000000000..55feefc4f12
--- /dev/null
+++ b/lib/public/FilesMetadata/IFilesMetadataManager.php
@@ -0,0 +1,169 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata;
+
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Files\Node;
+use OCP\FilesMetadata\Exceptions\FilesMetadataException;
+use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
+use OCP\FilesMetadata\Model\IFilesMetadata;
+use OCP\FilesMetadata\Model\IMetadataValueWrapper;
+
+/**
+ * Manager for FilesMetadata; manage files' metadata.
+ *
+ * @since 28.0.0
+ */
+interface IFilesMetadataManager {
+ /** @since 28.0.0 */
+ public const PROCESS_LIVE = 1;
+ /** @since 28.0.0 */
+ public const PROCESS_BACKGROUND = 2;
+ /** @since 28.0.0 */
+ public const PROCESS_NAMED = 4;
+
+ /**
+ * initiate the process of refreshing the metadata in relation to a node
+ * usually, this process:
+ * - get current metadata from database, if available, or create a new one
+ * - dispatch a MetadataLiveEvent,
+ * - save new metadata in database, if metadata have been changed during the event
+ * - refresh metadata indexes if needed,
+ * - prep a new cronjob if an app request it during the event,
+ *
+ * @param Node $node related node
+ * @param int $process type of process
+ * @param string $namedEvent limit process to a named event
+ *
+ * @return IFilesMetadata
+ * @see self::PROCESS_BACKGROUND
+ * @see self::PROCESS_LIVE
+ * @see self::PROCESS_NAMED
+ * @since 28.0.0
+ */
+ public function refreshMetadata(
+ Node $node,
+ int $process = self::PROCESS_LIVE,
+ string $namedEvent = ''
+ ): IFilesMetadata;
+
+ /**
+ * returns metadata of a file id
+ *
+ * @param int $fileId file id
+ * @param boolean $generate Generate if metadata does not exist
+ *
+ * @return IFilesMetadata
+ * @throws FilesMetadataNotFoundException if not found
+ * @since 28.0.0
+ */
+ public function getMetadata(int $fileId, bool $generate = false): IFilesMetadata;
+
+ /**
+ * returns metadata of multiple file ids
+ *
+ * @param int[] $fileIds file ids
+ *
+ * @return array File ID is the array key, files without metadata are not returned in the array
+ * @psalm-return array<int, IFilesMetadata>
+ * @since 28.0.0
+ */
+ public function getMetadataForFiles(array $fileIds): array;
+
+ /**
+ * save metadata to database and refresh indexes.
+ * metadata are saved if new data are available.
+ * on update, a check on syncToken is done to avoid conflict (race condition)
+ *
+ * @param IFilesMetadata $filesMetadata
+ *
+ * @throws FilesMetadataException if metadata seems malformed
+ * @since 28.0.0
+ */
+ public function saveMetadata(IFilesMetadata $filesMetadata): void;
+
+ /**
+ * delete metadata and its indexes
+ *
+ * @param int $fileId file id
+ *
+ * @return void
+ * @since 28.0.0
+ */
+ public function deleteMetadata(int $fileId): void;
+
+ /**
+ * generate and return a MetadataQuery to help building sql queries
+ *
+ * @param IQueryBuilder $qb
+ * @param string $fileTableAlias alias of the table that contains data about files
+ * @param string $fileIdField alias of the field that contains file ids
+ *
+ * @return IMetadataQuery|null NULL if table are not set yet or never used
+ * @see IMetadataQuery
+ * @since 28.0.0
+ */
+ public function getMetadataQuery(
+ IQueryBuilder $qb,
+ string $fileTableAlias,
+ string $fileIdField
+ ): ?IMetadataQuery;
+
+ /**
+ * returns all type of metadata currently available.
+ * The list is stored in a IFilesMetadata with null values but correct type.
+ *
+ * @return IFilesMetadata
+ * @since 28.0.0
+ */
+ public function getKnownMetadata(): IFilesMetadata;
+
+ /**
+ * initiate a metadata key with its type.
+ * The call is mandatory before using the metadata property in a webdav request.
+ * It is not needed to only use this method when the app is enabled: the method can be
+ * called each time during the app loading as the metadata will only be initiated if not known
+ *
+ * @param string $key metadata key
+ * @param string $type metadata type
+ * @param bool $indexed TRUE if metadata can be search
+ * @param int $editPermission remote edit permission via Webdav PROPPATCH
+ *
+ * @see IMetadataValueWrapper::TYPE_INT
+ * @see IMetadataValueWrapper::TYPE_FLOAT
+ * @see IMetadataValueWrapper::TYPE_BOOL
+ * @see IMetadataValueWrapper::TYPE_ARRAY
+ * @see IMetadataValueWrapper::TYPE_STRING_LIST
+ * @see IMetadataValueWrapper::TYPE_INT_LIST
+ * @see IMetadataValueWrapper::TYPE_STRING
+ * @see IMetadataValueWrapper::EDIT_FORBIDDEN
+ * @see IMetadataValueWrapper::EDIT_REQ_OWNERSHIP
+ * @see IMetadataValueWrapper::EDIT_REQ_WRITE_PERMISSION
+ * @see IMetadataValueWrapper::EDIT_REQ_READ_PERMISSION
+ * @since 28.0.0
+ */
+ public function initMetadata(string $key, string $type, bool $indexed, int $editPermission): void;
+}
diff --git a/lib/public/FilesMetadata/IMetadataQuery.php b/lib/public/FilesMetadata/IMetadataQuery.php
new file mode 100644
index 00000000000..c1c649ac243
--- /dev/null
+++ b/lib/public/FilesMetadata/IMetadataQuery.php
@@ -0,0 +1,92 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata;
+
+use OCP\FilesMetadata\Model\IFilesMetadata;
+
+/**
+ * Model that help building queries with metadata and metadata indexes
+ *
+ * @since 28.0.0
+ */
+interface IMetadataQuery {
+ /** @since 28.0.0 */
+ public const EXTRA = 'metadata';
+
+ /**
+ * Add metadata linked to file id to the query
+ *
+ * @see self::extractMetadata()
+ * @since 28.0.0
+ */
+ public function retrieveMetadata(): void;
+
+ /**
+ * extract metadata from a result row
+ *
+ * @param array $row result row
+ *
+ * @return IFilesMetadata metadata
+ * @see self::retrieveMetadata()
+ * @since 28.0.0
+ */
+ public function extractMetadata(array $row): IFilesMetadata;
+
+ /**
+ * join the metadata_index table, based on a metadataKey.
+ * This will prep the query for condition based on this specific metadataKey.
+ * If a link to the metadataKey already exists, returns known alias.
+ *
+ * TODO: investigate how to support a search done on multiple values for same key (AND).
+ *
+ * @param string $metadataKey metadata key
+ * @param bool $enforce limit the request only to existing metadata
+ *
+ * @return string generated table alias
+ * @since 28.0.0
+ */
+ public function joinIndex(string $metadataKey, bool $enforce = false): string;
+
+ /**
+ * returns the name of the field for metadata key to be used in query expressions
+ *
+ * @param string $metadataKey metadata key
+ *
+ * @return string table field
+ * @since 28.0.0
+ */
+ public function getMetadataKeyField(string $metadataKey): string;
+
+ /**
+ * returns the name of the field for metadata string value to be used in query expressions
+ *
+ * @param string $metadataKey metadata key
+ *
+ * @return string table field
+ * @since 28.0.0
+ */
+ public function getMetadataValueField(string $metadataKey): string;
+}
diff --git a/lib/public/FilesMetadata/Model/IFilesMetadata.php b/lib/public/FilesMetadata/Model/IFilesMetadata.php
new file mode 100644
index 00000000000..024b21039bc
--- /dev/null
+++ b/lib/public/FilesMetadata/Model/IFilesMetadata.php
@@ -0,0 +1,386 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Model;
+
+use JsonSerializable;
+use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
+use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException;
+
+/**
+ * Model that represent metadata linked to a specific file.
+ *
+ * Example of json stored in the database
+ * {
+ * "mymeta": {
+ * "value": "this is a test",
+ * "type": "string",
+ * "etag": "abcd1234",
+ * "indexed": false,
+ * "editPermission": 1
+ * },
+ * "myapp-anothermeta": {
+ * "value": 42,
+ * "type": "int",
+ * "etag": "0987zyxw",
+ * "indexed": true,
+ * "editPermission": 0
+ * }
+ * }
+ *
+ * @see IMetadataValueWrapper
+ * @since 28.0.0
+ */
+interface IFilesMetadata extends JsonSerializable {
+ /**
+ * returns the file id linked to this metadata
+ *
+ * @return int related file id
+ * @since 28.0.0
+ */
+ public function getFileId(): int;
+
+ /**
+ * returns last time metadata were updated in the database
+ *
+ * @return int timestamp
+ * @since 28.0.0
+ */
+ public function lastUpdateTimestamp(): int;
+
+ /**
+ * returns the token known at the time the metadata were extracted from database
+ *
+ * @return string token
+ * @since 28.0.0
+ */
+ public function getSyncToken(): string;
+
+ /**
+ * returns all current metadata keys
+ *
+ * @return string[] list of keys
+ * @since 28.0.0
+ */
+ public function getKeys(): array;
+
+ /**
+ * returns true if search metadata key exists
+ *
+ * @param string $needle metadata key to search
+ *
+ * @return bool TRUE if key exist
+ * @since 28.0.0
+ */
+ public function hasKey(string $needle): bool;
+
+ /**
+ * return the list of metadata keys set as indexed
+ *
+ * @return string[] list of indexes
+ * @since 28.0.0
+ */
+ public function getIndexes(): array;
+
+ /**
+ * returns true if key exists and is set as indexed
+ *
+ * @param string $key metadata key
+ *
+ * @return bool
+ * @since 28.0.0
+ */
+ public function isIndex(string $key): bool;
+
+ /**
+ * returns file etag stored during the last update of the metadata key
+ *
+ * @param string $key metadata key
+ * @return string
+ * @since 29.0.0
+ */
+ public function getEtag(string $key): string;
+
+ /**
+ * set file etag
+ *
+ * @param string $key metadata key
+ * @since 29.0.0
+ */
+ public function setEtag(string $key, string $etag): void;
+
+ /**
+ * set remote edit permission
+ * (Webdav PROPPATCH)
+ *
+ * @param string $key metadata key
+ * @param int $permission remote edit permission
+ *
+ * @since 28.0.0
+ */
+ public function setEditPermission(string $key, int $permission): void;
+
+ /**
+ * returns remote edit permission
+ * (Webdav PROPPATCH)
+ *
+ * @param string $key metadata key
+ *
+ * @return int
+ * @since 28.0.0
+ */
+ public function getEditPermission(string $key): int;
+
+ /**
+ * returns string value for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return string metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getString(string $key): string;
+
+ /**
+ * returns int value for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return int metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getInt(string $key): int;
+
+ /**
+ * returns float value for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return float metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getFloat(string $key): float;
+
+ /**
+ * returns bool value for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return bool metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getBool(string $key): bool;
+
+ /**
+ * returns array for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return array metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getArray(string $key): array;
+
+ /**
+ * returns string[] value for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return string[] metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getStringList(string $key): array;
+
+ /**
+ * returns int[] value for a metadata key
+ *
+ * @param string $key metadata key
+ *
+ * @return int[] metadata value
+ * @throws FilesMetadataNotFoundException
+ * @throws FilesMetadataTypeException
+ * @since 28.0.0
+ */
+ public function getIntList(string $key): array;
+
+ /**
+ * returns the value type of the metadata (string, int, ...)
+ *
+ * @param string $key metadata key
+ *
+ * @return string value type
+ * @throws FilesMetadataNotFoundException
+ * @see IMetadataValueWrapper::TYPE_STRING
+ * @see IMetadataValueWrapper::TYPE_INT
+ * @see IMetadataValueWrapper::TYPE_FLOAT
+ * @see IMetadataValueWrapper::TYPE_BOOL
+ * @see IMetadataValueWrapper::TYPE_ARRAY
+ * @see IMetadataValueWrapper::TYPE_STRING_LIST
+ * @see IMetadataValueWrapper::TYPE_INT_LIST
+ * @since 28.0.0
+ */
+ public function getType(string $key): string;
+
+ /**
+ * set a metadata key/value pair for string value
+ *
+ * @param string $key metadata key
+ * @param string $value metadata value
+ * @param bool $index set TRUE if value must be indexed
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setString(string $key, string $value, bool $index = false): self;
+
+ /**
+ * set a metadata key/value pair for int value
+ *
+ * @param string $key metadata key
+ * @param int $value metadata value
+ * @param bool $index set TRUE if value must be indexed
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setInt(string $key, int $value, bool $index = false): self;
+
+ /**
+ * set a metadata key/value pair for float value
+ *
+ * @param string $key metadata key
+ * @param float $value metadata value
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setFloat(string $key, float $value): self;
+
+ /**
+ * set a metadata key/value pair for bool value
+ *
+ * @param string $key metadata key
+ * @param bool $value metadata value
+ * @param bool $index set TRUE if value must be indexed
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setBool(string $key, bool $value, bool $index = false): self;
+
+ /**
+ * set a metadata key/value pair for array
+ *
+ * @param string $key metadata key
+ * @param array $value metadata value
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setArray(string $key, array $value): self;
+
+ /**
+ * set a metadata key/value pair for list of string
+ *
+ * @param string $key metadata key
+ * @param string[] $value metadata value
+ * @param bool $index set TRUE if each values from the list must be indexed
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setStringList(string $key, array $value, bool $index = false): self;
+
+ /**
+ * set a metadata key/value pair for list of int
+ *
+ * @param string $key metadata key
+ * @param int[] $value metadata value
+ * @param bool $index set TRUE if each values from the list must be indexed
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setIntList(string $key, array $value, bool $index = false): self;
+
+ /**
+ * unset a metadata
+ *
+ * @param string $key metadata key
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function unset(string $key): self;
+
+ /**
+ * unset metadata with key starting with prefix
+ *
+ * @param string $keyPrefix metadata key prefix
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function removeStartsWith(string $keyPrefix): self;
+
+ /**
+ * returns true if object have been updated since last import
+ *
+ * @return bool TRUE if metadata have been modified
+ * @since 28.0.0
+ */
+ public function updated(): bool;
+
+ /**
+ * returns metadata in a simple array with METADATA_KEY => METADATA_VALUE
+ *
+ * @return array metadata
+ * @since 28.0.0
+ */
+ public function asArray(): array;
+
+ /**
+ * deserialize the object from a json
+ *
+ * @param array $data serialized version of the object
+ *
+ * @return self
+ * @see jsonSerialize
+ * @since 28.0.0
+ */
+ public function import(array $data): self;
+}
diff --git a/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php b/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php
new file mode 100644
index 00000000000..6c551efea81
--- /dev/null
+++ b/lib/public/FilesMetadata/Model/IMetadataValueWrapper.php
@@ -0,0 +1,352 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\FilesMetadata\Model;
+
+use JsonSerializable;
+use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
+use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException;
+
+/**
+ * Model that store the value of a single metadata.
+ * It stores the value, its type and the index status.
+ *
+ * @see IFilesMetadata
+ * @since 28.0.0
+ */
+interface IMetadataValueWrapper extends JsonSerializable {
+ /** @since 28.0.0 */
+ public const TYPE_STRING = 'string';
+ /** @since 28.0.0 */
+ public const TYPE_INT = 'int';
+ /** @since 28.0.0 */
+ public const TYPE_FLOAT = 'float';
+ /** @since 28.0.0 */
+ public const TYPE_BOOL = 'bool';
+ /** @since 28.0.0 */
+ public const TYPE_ARRAY = 'array';
+ /** @since 28.0.0 */
+ public const TYPE_STRING_LIST = 'string[]';
+ /** @since 28.0.0 */
+ public const TYPE_INT_LIST = 'int[]';
+
+ /** @since 28.0.0 */
+ public const EDIT_FORBIDDEN = 0;
+ /** @since 28.0.0 */
+ public const EDIT_REQ_OWNERSHIP = 1;
+ /** @since 28.0.0 */
+ public const EDIT_REQ_WRITE_PERMISSION = 2;
+ /** @since 28.0.0 */
+ public const EDIT_REQ_READ_PERMISSION = 3;
+
+
+ /**
+ * Unless a call of import() to deserialize an object is expected, a valid value type is needed here.
+ *
+ * @param string $type value type
+ *
+ * @see self::TYPE_INT
+ * @see self::TYPE_FLOAT
+ * @see self::TYPE_BOOL
+ * @see self::TYPE_ARRAY
+ * @see self::TYPE_STRING_LIST
+ * @see self::TYPE_INT_LIST
+ * @see self::TYPE_STRING
+ * @since 28.0.0
+ */
+ public function __construct(string $type);
+
+ /**
+ * returns the value type
+ *
+ * @return string value type
+ * @see self::TYPE_INT
+ * @see self::TYPE_FLOAT
+ * @see self::TYPE_BOOL
+ * @see self::TYPE_ARRAY
+ * @see self::TYPE_STRING_LIST
+ * @see self::TYPE_INT_LIST
+ * @see self::TYPE_STRING
+ * @since 28.0.0
+ */
+ public function getType(): string;
+
+ /**
+ * returns if the set value type is the one expected
+ *
+ * @param string $type value type
+ *
+ * @return bool
+ * @see self::TYPE_INT
+ * @see self::TYPE_FLOAT
+ * @see self::TYPE_BOOL
+ * @see self::TYPE_ARRAY
+ * @see self::TYPE_STRING_LIST
+ * @see self::TYPE_INT_LIST
+ * @see self::TYPE_STRING
+ * @since 28.0.0
+ */
+ public function isType(string $type): bool;
+
+ /**
+ * throws an exception if the type is not correctly set
+ *
+ * @param string $type value type
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if type cannot be confirmed
+ * @see self::TYPE_INT
+ * @see self::TYPE_BOOL
+ * @see self::TYPE_ARRAY
+ * @see self::TYPE_STRING_LIST
+ * @see self::TYPE_INT_LIST
+ * @see self::TYPE_STRING
+ * @see self::TYPE_FLOAT
+ * @since 28.0.0
+ */
+ public function assertType(string $type): self;
+
+ /**
+ * set a string value
+ *
+ * @param string $value string to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store a string
+ * @since 28.0.0
+ */
+ public function setValueString(string $value): self;
+
+ /**
+ * set a int value
+ *
+ * @param int $value int to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store an int
+ * @since 28.0.0
+ */
+ public function setValueInt(int $value): self;
+
+ /**
+ * set a float value
+ *
+ * @param float $value float to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store a float
+ * @since 28.0.0
+ */
+ public function setValueFloat(float $value): self;
+
+ /**
+ * set a bool value
+ *
+ * @param bool $value bool to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store a bool
+ * @since 28.0.0
+ */
+ public function setValueBool(bool $value): self;
+
+ /**
+ * set an array value
+ *
+ * @param array $value array to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store an array
+ * @since 28.0.0
+ */
+ public function setValueArray(array $value): self;
+
+ /**
+ * set a string list value
+ *
+ * @param string[] $value string list to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store a string list
+ * @since 28.0.0
+ */
+ public function setValueStringList(array $value): self;
+
+ /**
+ * set an int list value
+ *
+ * @param int[] $value int list to be set as value
+ *
+ * @return self
+ * @throws FilesMetadataTypeException if wrapper was not set to store an int list
+ * @since 28.0.0
+ */
+ public function setValueIntList(array $value): self;
+
+
+ /**
+ * get stored value
+ *
+ * @return string set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store a string
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueString(): string;
+
+ /**
+ * get stored value
+ *
+ * @return int set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store an int
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueInt(): int;
+
+ /**
+ * get stored value
+ *
+ * @return float set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store a float
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueFloat(): float;
+
+ /**
+ * get stored value
+ *
+ * @return bool set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store a bool
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueBool(): bool;
+
+ /**
+ * get stored value
+ *
+ * @return array set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store an array
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueArray(): array;
+
+ /**
+ * get stored value
+ *
+ * @return string[] set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store a string list
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueStringList(): array;
+
+ /**
+ * get stored value
+ *
+ * @return int[] set value
+ * @throws FilesMetadataTypeException if wrapper was not set to store an int list
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueIntList(): array;
+
+ /**
+ * get stored value
+ *
+ * @return string|int|float|bool|array|string[]|int[] set value
+ * @throws FilesMetadataNotFoundException if value is not set
+ * @since 28.0.0
+ */
+ public function getValueAny(): mixed;
+
+ /**
+ * get stored etag value
+ *
+ * @return string stored etag
+ * @since 29.0.0
+ */
+ public function getEtag(): string;
+
+ /**
+ * set etag value
+ *
+ * @param string $etag etag value
+ *
+ * @return self
+ * @since 29.0.0
+ */
+ public function setEtag(string $etag): self;
+
+ /**
+ * @param bool $indexed TRUE to set the stored value as an indexed value
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setIndexed(bool $indexed): self;
+
+ /**
+ * returns if value is an indexed value
+ *
+ * @return bool TRUE if value is an indexed value
+ * @since 28.0.0
+ */
+ public function isIndexed(): bool;
+
+ /**
+ * set remote edit permission
+ * (Webdav PROPPATCH)
+ *
+ * @param int $permission edit permission
+ *
+ * @return self
+ * @since 28.0.0
+ */
+ public function setEditPermission(int $permission): self;
+
+ /**
+ * get remote edit permission
+ * (Webdav PROPPATCH)
+ *
+ * @return int edit permission
+ * @since 28.0.0
+ */
+ public function getEditPermission(): int;
+
+ /**
+ * deserialize the object from a json
+ *
+ * @param array $data serialized version of the object
+ *
+ * @return self
+ * @see jsonSerialize
+ * @since 28.0.0
+ */
+ public function import(array $data): self;
+}
diff --git a/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php b/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php
new file mode 100644
index 00000000000..cf3c5905135
--- /dev/null
+++ b/lib/public/FullTextSearch/Exceptions/FullTextSearchIndexNotAvailableException.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023, Faraz Samapoor <f.samapoor@gmail.com>
+ *
+ * @author Faraz Samapoor <f.samapoor@gmail.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\FullTextSearch\Exceptions;
+
+/**
+ * @since 28.0.0
+ *
+ * Class FullTextSearchIndexNotAvailableException
+ *
+ */
+class FullTextSearchIndexNotAvailableException extends \Exception {
+}
diff --git a/lib/public/FullTextSearch/Model/IIndex.php b/lib/public/FullTextSearch/Model/IIndex.php
index dad10c934de..6403d408a80 100644
--- a/lib/public/FullTextSearch/Model/IIndex.php
+++ b/lib/public/FullTextSearch/Model/IIndex.php
@@ -43,24 +43,84 @@ namespace OCP\FullTextSearch\Model;
*
*/
interface IIndex {
+ /**
+ * @since 15.0.0
+ */
public const INDEX_OK = 1;
+
+ /**
+ * @since 15.0.0
+ */
public const INDEX_IGNORE = 2;
+ /**
+ * @since 15.0.0
+ */
public const INDEX_META = 4;
+
+ /**
+ * @since 15.0.0
+ */
public const INDEX_CONTENT = 8;
+
+ /**
+ * @since 16.0.0
+ */
public const INDEX_PARTS = 16;
+
+ /**
+ * @since 15.0.0
+ */
public const INDEX_FULL = 28;
+
+ /**
+ * @since 15.0.0
+ */
public const INDEX_REMOVE = 32;
+
+ /**
+ * @since 15.0.0
+ */
public const INDEX_DONE = 64;
+
+ /**
+ * @since 15.0.0
+ */
public const INDEX_FAILED = 128;
+ /**
+ * @since 15.0.0
+ */
public const ERROR_FAILED = 1;
+
+ /**
+ * @since 15.0.0
+ */
public const ERROR_FAILED2 = 2;
+
+ /**
+ * @since 15.0.0
+ */
public const ERROR_FAILED3 = 4;
+ /**
+ * @since 15.0.0
+ */
public const ERROR_SEV_1 = 1;
+
+ /**
+ * @since 15.0.0
+ */
public const ERROR_SEV_2 = 2;
+
+ /**
+ * @since 15.0.0
+ */
public const ERROR_SEV_3 = 3;
+
+ /**
+ * @since 15.0.0
+ */
public const ERROR_SEV_4 = 4;
diff --git a/lib/public/FullTextSearch/Model/IIndexDocument.php b/lib/public/FullTextSearch/Model/IIndexDocument.php
index b659c2b33f1..b043c7d8bb1 100644
--- a/lib/public/FullTextSearch/Model/IIndexDocument.php
+++ b/lib/public/FullTextSearch/Model/IIndexDocument.php
@@ -41,7 +41,14 @@ namespace OCP\FullTextSearch\Model;
* @since 15.0.0
*/
interface IIndexDocument {
+ /**
+ * @since 15.0.0
+ */
public const NOT_ENCODED = 0;
+
+ /**
+ * @since 15.0.0
+ */
public const ENCODED_BASE64 = 1;
diff --git a/lib/public/FullTextSearch/Model/IRunner.php b/lib/public/FullTextSearch/Model/IRunner.php
index c03126500cb..09782e27275 100644
--- a/lib/public/FullTextSearch/Model/IRunner.php
+++ b/lib/public/FullTextSearch/Model/IRunner.php
@@ -40,8 +40,19 @@ namespace OCP\FullTextSearch\Model;
*
*/
interface IRunner {
+ /**
+ * @since 15.0.0
+ */
public const RESULT_TYPE_SUCCESS = 1;
+
+ /**
+ * @since 15.0.0
+ */
public const RESULT_TYPE_WARNING = 4;
+
+ /**
+ * @since 15.0.0
+ */
public const RESULT_TYPE_FAIL = 9;
diff --git a/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php b/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php
index 91f3c6dfe1b..15c5f98d7b8 100644
--- a/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php
+++ b/lib/public/FullTextSearch/Model/ISearchRequestSimpleQuery.php
@@ -38,16 +38,59 @@ namespace OCP\FullTextSearch\Model;
*
*/
interface ISearchRequestSimpleQuery {
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_TEXT = 1;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_KEYWORD = 2;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_INT_EQ = 3;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_INT_GTE = 4;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_INT_GT = 5;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_INT_LTE = 6;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_INT_LT = 7;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_BOOL = 8;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_ARRAY = 9;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_REGEX = 10;
+
+ /**
+ * @since 17.0.0
+ */
public const COMPARE_TYPE_WILDCARD = 11;
diff --git a/lib/public/Group/Backend/ABackend.php b/lib/public/Group/Backend/ABackend.php
index 7f5cf732335..274b98655e4 100644
--- a/lib/public/Group/Backend/ABackend.php
+++ b/lib/public/Group/Backend/ABackend.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Carl Schwan <carl@carlschwan.eu>
*
* @license GNU AGPL version 3 or any later version
*
@@ -30,7 +31,7 @@ use OCP\GroupInterface;
/**
* @since 14.0.0
*/
-abstract class ABackend implements GroupInterface {
+abstract class ABackend implements GroupInterface, IBatchMethodsBackend {
/**
* @deprecated 14.0.0
* @since 14.0.0
@@ -65,4 +66,29 @@ abstract class ABackend implements GroupInterface {
return (bool)($actions & $implements);
}
+
+ /**
+ * @since 28.0.0
+ */
+ public function groupsExists(array $gids): array {
+ return array_values(array_filter(
+ $gids,
+ fn (string $gid): bool => $this->groupExists($gid),
+ ));
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getGroupsDetails(array $gids): array {
+ if (!($this instanceof IGroupDetailsBackend || $this->implementsActions(GroupInterface::GROUP_DETAILS))) {
+ throw new \Exception("Should not have been called");
+ }
+ /** @var IGroupDetailsBackend $this */
+ $groupData = [];
+ foreach ($gids as $gid) {
+ $groupData[$gid] = $this->getGroupDetails($gid);
+ }
+ return $groupData;
+ }
}
diff --git a/lib/public/Group/Backend/IBatchMethodsBackend.php b/lib/public/Group/Backend/IBatchMethodsBackend.php
new file mode 100644
index 00000000000..2af00e42825
--- /dev/null
+++ b/lib/public/Group/Backend/IBatchMethodsBackend.php
@@ -0,0 +1,61 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Group\Backend;
+
+/**
+ * @brief Optional interface for group backends
+ * @since 28.0.0
+ */
+interface IBatchMethodsBackend {
+ /**
+ * @brief Batch method to check if a list of groups exists
+ *
+ * The default implementation in ABackend will just call groupExists in
+ * a loop. But a GroupBackend implementation should provides a more optimized
+ * override this method to provide a more optimized way to execute this operation.
+ *
+ * @param list<string> $gids
+ * @return list<string> the list of group that exists
+ * @since 28.0.0
+ */
+ public function groupsExists(array $gids): array;
+
+ /**
+ * @brief Batch method to get the group details of a list of groups
+ *
+ * The default implementation in ABackend will just call getGroupDetails in
+ * a loop. But a GroupBackend implementation should override this method
+ * to provide a more optimized way to execute this operation.
+ *
+ * @throw \RuntimeException if called on a backend that doesn't implements IGroupDetailsBackend
+ *
+ * @return array<string, array{displayName?: string}>
+ * @since 28.0.0
+ */
+ public function getGroupsDetails(array $gids): array;
+}
diff --git a/lib/public/Group/Backend/IGroupDetailsBackend.php b/lib/public/Group/Backend/IGroupDetailsBackend.php
index 4852f978195..851c10388e0 100644
--- a/lib/public/Group/Backend/IGroupDetailsBackend.php
+++ b/lib/public/Group/Backend/IGroupDetailsBackend.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Carl Schwan <carl@carlschwan.eu>
*
* @license GNU AGPL version 3 or any later version
*
@@ -26,10 +27,17 @@ declare(strict_types=1);
namespace OCP\Group\Backend;
/**
+ * @brief Optional interface for group backends
* @since 14.0.0
*/
interface IGroupDetailsBackend {
/**
+ * @brief Get additional details for a group, for example the display name.
+ *
+ * The array returned can be empty when no additional information is available
+ * for the group.
+ *
+ * @return array{displayName?: string}
* @since 14.0.0
*/
public function getGroupDetails(string $gid): array;
diff --git a/lib/public/GroupInterface.php b/lib/public/GroupInterface.php
index a18d38df002..764c810f986 100644
--- a/lib/public/GroupInterface.php
+++ b/lib/public/GroupInterface.php
@@ -38,15 +38,44 @@ namespace OCP;
interface GroupInterface {
/**
* actions that user backends can define
+ *
+ * @since 12.0.0
*/
public const CREATE_GROUP = 0x00000001;
+
+ /**
+ * @since 12.0.0
+ */
public const DELETE_GROUP = 0x00000010;
+
+ /**
+ * @since 12.0.0
+ */
public const ADD_TO_GROUP = 0x00000100;
+
+ /**
+ * @since 12.0.0
+ * @deprecated 29.0.0
+ */
public const REMOVE_FROM_GOUP = 0x00001000; // oops
+
+ /**
+ * @since 12.0.0
+ */
public const REMOVE_FROM_GROUP = 0x00001000;
+
//OBSOLETE const GET_DISPLAYNAME = 0x00010000;
+
+ /**
+ * @since 12.0.0
+ */
public const COUNT_USERS = 0x00100000;
+
+ /**
+ * @since 12.0.0
+ */
public const GROUP_DETAILS = 0x01000000;
+
/**
* @since 13.0.0
*/
@@ -86,7 +115,8 @@ interface GroupInterface {
public function getUserGroups($uid);
/**
- * get a list of all groups
+ * @brief Get a list of all groups
+ *
* @param string $search
* @param int $limit
* @param int $offset
@@ -98,7 +128,8 @@ interface GroupInterface {
public function getGroups(string $search = '', int $limit = -1, int $offset = 0);
/**
- * check if a group exists
+ * @brief Check if a group exists
+ *
* @param string $gid
* @return bool
* @since 4.5.0
diff --git a/lib/public/Http/Client/IClient.php b/lib/public/Http/Client/IClient.php
index fb1760c25f2..c6b7cafe73f 100644
--- a/lib/public/Http/Client/IClient.php
+++ b/lib/public/Http/Client/IClient.php
@@ -208,6 +208,47 @@ interface IClient {
public function options(string $uri, array $options = []): IResponse;
/**
+ * Get the response of a Throwable thrown by the request methods when possible
+ *
+ * @param \Throwable $e
+ * @return IResponse
+ * @throws \Throwable When $e did not have a response
+ * @since 29.0.0
+ */
+ public function getResponseFromThrowable(\Throwable $e): IResponse;
+
+ /**
+ * Sends a HTTP request
+ * @param string $method The HTTP method to use
+ * @param string $uri
+ * @param array $options Array such as
+ * 'query' => [
+ * 'field' => 'abc',
+ * 'other_field' => '123',
+ * 'file_name' => fopen('/path/to/file', 'r'),
+ * ],
+ * 'headers' => [
+ * 'foo' => 'bar',
+ * ],
+ * 'cookies' => [
+ * 'foo' => 'bar',
+ * ],
+ * 'allow_redirects' => [
+ * 'max' => 10, // allow at most 10 redirects.
+ * 'strict' => true, // use "strict" RFC compliant redirects.
+ * 'referer' => true, // add a Referer header
+ * 'protocols' => ['https'] // only allow https URLs
+ * ],
+ * 'sink' => '/path/to/file', // save to a file or a stream
+ * 'verify' => true, // bool or string to CA file
+ * 'debug' => true,
+ * @return IResponse
+ * @throws \Exception If the request could not get completed
+ * @since 29.0.0
+ */
+ public function request(string $method, string $uri, array $options = []): IResponse;
+
+ /**
* Sends an asynchronous GET request
* @param string $uri
* @param array $options Array such as
diff --git a/lib/public/Http/WellKnown/JrdResponse.php b/lib/public/Http/WellKnown/JrdResponse.php
index 7a25f8fe0c3..077b58dc1d9 100644
--- a/lib/public/Http/WellKnown/JrdResponse.php
+++ b/lib/public/Http/WellKnown/JrdResponse.php
@@ -127,10 +127,10 @@ final class JrdResponse implements IResponse {
* @since 21.0.0
*/
public function addLink(string $rel,
- ?string $type,
- ?string $href,
- ?array $titles = [],
- ?array $properties = []): self {
+ ?string $type,
+ ?string $href,
+ ?array $titles = [],
+ ?array $properties = []): self {
$this->links[] = array_filter([
'rel' => $rel,
'type' => $type,
diff --git a/lib/public/IAppConfig.php b/lib/public/IAppConfig.php
index cf387a8a44c..afcdf67f92c 100644
--- a/lib/public/IAppConfig.php
+++ b/lib/public/IAppConfig.php
@@ -1,9 +1,12 @@
<?php
+
+declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Bart Visscher <bartv@thisnet.nl>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
@@ -26,28 +29,486 @@
*/
namespace OCP;
+use OCP\Exceptions\AppConfigUnknownKeyException;
+
/**
* This class provides an easy way for apps to store config values in the
* database.
+ *
+ * **Note:** since 29.0.0, it supports **lazy loading**
+ *
+ * ### What is lazy loading ?
+ * In order to avoid loading useless config values into memory for each request,
+ * only non-lazy values are now loaded.
+ *
+ * Once a value that is lazy is requested, all lazy values will be loaded.
+ *
+ * Similarly, some methods from this class are marked with a warning about ignoring
+ * lazy loading. Use them wisely and only on parts of the code that are called
+ * during specific requests or actions to avoid loading the lazy values all the time.
+ *
* @since 7.0.0
+ * @since 29.0.0 - Supporting types and lazy loading
*/
interface IAppConfig {
+ /** @since 29.0.0 */
+ public const VALUE_SENSITIVE = 1;
+ /** @since 29.0.0 */
+ public const VALUE_MIXED = 2;
+ /** @since 29.0.0 */
+ public const VALUE_STRING = 4;
+ /** @since 29.0.0 */
+ public const VALUE_INT = 8;
+ /** @since 29.0.0 */
+ public const VALUE_FLOAT = 16;
+ /** @since 29.0.0 */
+ public const VALUE_BOOL = 32;
+ /** @since 29.0.0 */
+ public const VALUE_ARRAY = 64;
+
/**
- * check if a key is set in the appconfig
- * @param string $app
- * @param string $key
- * @return bool
+ * Get list of all apps that have at least one config value stored in database
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @return string[] list of app ids
* @since 7.0.0
*/
- public function hasKey($app, $key);
+ public function getApps(): array;
+
+ /**
+ * Returns all keys stored in database, related to an app.
+ * Please note that the values are not returned.
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $app id of the app
+ *
+ * @return string[] list of stored config keys
+ * @since 29.0.0
+ */
+ public function getKeys(string $app): array;
+
+ /**
+ * Check if a key exists in the list of stored config values.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return bool TRUE if key exists
+ * @since 29.0.0 Added the $lazy argument
+ * @since 7.0.0
+ */
+ public function hasKey(string $app, string $key, ?bool $lazy = false): bool;
+
+ /**
+ * best way to see if a value is set as sensitive (not displayed in report)
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param bool|null $lazy search within lazy loaded config
+ *
+ * @return bool TRUE if value is sensitive
+ * @throws AppConfigUnknownKeyException if config key is not known
+ * @since 29.0.0
+ */
+ public function isSensitive(string $app, string $key, ?bool $lazy = false): bool;
+
+ /**
+ * Returns if the config key stored in database is lazy loaded
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ *
+ * @return bool TRUE if config is lazy loaded
+ * @throws AppConfigUnknownKeyException if config key is not known
+ * @see IAppConfig for details about lazy loading
+ * @since 29.0.0
+ */
+ public function isLazy(string $app, string $key): bool;
+
+ /**
+ * List all config values from an app with config key starting with $key.
+ * Returns an array with config key as key, stored value as value.
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $app id of the app
+ * @param string $prefix config keys prefix to search, can be empty.
+ * @param bool $filtered filter sensitive config values
+ *
+ * @return array<string, string> [configKey => configValue]
+ * @since 29.0.0
+ */
+ public function getAllValues(string $app, string $prefix = '', bool $filtered = false): array;
+
+ /**
+ * List all apps storing a specific config key and its stored value.
+ * Returns an array with appId as key, stored value as value.
+ *
+ * @param string $key config key
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return array<string, string|int|float|bool|array> [appId => configValue]
+ * @since 29.0.0
+ */
+ public function searchValues(string $key, bool $lazy = false): array;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param string $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return string stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see getValueInt()
+ * @see getValueFloat()
+ * @see getValueBool()
+ * @see getValueArray()
+ */
+ public function getValueString(string $app, string $key, string $default = '', bool $lazy = false): string;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param int $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return int stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see getValueString()
+ * @see getValueFloat()
+ * @see getValueBool()
+ * @see getValueArray()
+ */
+ public function getValueInt(string $app, string $key, int $default = 0, bool $lazy = false): int;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param float $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return float stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see getValueString()
+ * @see getValueInt()
+ * @see getValueBool()
+ * @see getValueArray()
+ */
+ public function getValueFloat(string $app, string $key, float $default = 0, bool $lazy = false): float;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param bool $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return bool stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see getValueString()
+ * @see getValueInt()
+ * @see getValueFloat()
+ * @see getValueArray()
+ */
+ public function getValueBool(string $app, string $key, bool $default = false, bool $lazy = false): bool;
+
+ /**
+ * Get config value assigned to a config key.
+ * If config key is not found in database, default value is returned.
+ * If config key is set as lazy loaded, the $lazy argument needs to be set to TRUE.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param array $default default value
+ * @param bool $lazy search within lazy loaded config
+ *
+ * @return array stored config value or $default if not set in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see getValueString()
+ * @see getValueInt()
+ * @see getValueFloat()
+ * @see getValueBool()
+ */
+ public function getValueArray(string $app, string $key, array $default = [], bool $lazy = false): array;
+
+ /**
+ * returns the type of config value
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ *
+ * @return int
+ * @throws AppConfigUnknownKeyException
+ * @since 29.0.0
+ * @see VALUE_STRING
+ * @see VALUE_INT
+ * @see VALUE_FLOAT
+ * @see VALUE_BOOL
+ * @see VALUE_ARRAY
+ */
+ public function getValueType(string $app, string $key): int;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param string $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see setValueInt()
+ * @see setValueFloat()
+ * @see setValueBool()
+ * @see setValueArray()
+ */
+ public function setValueString(string $app, string $key, string $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * When handling huge value around and/or above 2,147,483,647, a debug log will be generated
+ * on 64bits system, as php int type reach its limit (and throw an exception) on 32bits when using huge numbers.
+ *
+ * When using huge numbers, it is advised to use {@see \OCP\Util::numericToNumber()} and {@see setValueString()}
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param int $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see setValueString()
+ * @see setValueFloat()
+ * @see setValueBool()
+ * @see setValueArray()
+ */
+ public function setValueInt(string $app, string $key, int $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * Store a config key and its value in database.
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param float $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see setValueString()
+ * @see setValueInt()
+ * @see setValueBool()
+ * @see setValueArray()
+ */
+ public function setValueFloat(string $app, string $key, float $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param bool $value config value
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see setValueString()
+ * @see setValueInt()
+ * @see setValueFloat()
+ * @see setValueArray()
+ */
+ public function setValueBool(string $app, string $key, bool $value, bool $lazy = false): bool;
+
+ /**
+ * Store a config key and its value in database
+ *
+ * If config key is already known with the exact same config value, the database is not updated.
+ * If config key is not supposed to be read during the boot of the cloud, it is advised to set it as lazy loaded.
+ *
+ * If config value was previously stored as sensitive or lazy loaded, status cannot be altered without using {@see deleteKey()} first
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param array $value config value
+ * @param bool $sensitive if TRUE value will be hidden when listing config values.
+ * @param bool $lazy set config as lazy loaded
+ *
+ * @return bool TRUE if value was different, therefor updated in database
+ * @since 29.0.0
+ * @see IAppConfig for explanation about lazy loading
+ * @see setValueString()
+ * @see setValueInt()
+ * @see setValueFloat()
+ * @see setValueBool()
+ */
+ public function setValueArray(string $app, string $key, array $value, bool $lazy = false, bool $sensitive = false): bool;
+
+ /**
+ * switch sensitive status of a config value
+ *
+ * **WARNING:** ignore lazy filtering, all config values are loaded from database
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param bool $sensitive TRUE to set as sensitive, FALSE to unset
+ *
+ * @return bool TRUE if database update were necessary
+ * @since 29.0.0
+ */
+ public function updateSensitive(string $app, string $key, bool $sensitive): bool;
+
+ /**
+ * switch lazy loading status of a config value
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @param bool $lazy TRUE to set as lazy loaded, FALSE to unset
+ *
+ * @return bool TRUE if database update was necessary
+ * @since 29.0.0
+ */
+ public function updateLazy(string $app, string $key, bool $lazy): bool;
+
+ /**
+ * returns an array contains details about a config value
+ *
+ * ```
+ * [
+ * "app" => "myapp",
+ * "key" => "mykey",
+ * "value" => "its_value",
+ * "lazy" => false,
+ * "type" => 4,
+ * "typeString" => "string",
+ * 'sensitive' => true
+ * ]
+ * ```
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ *
+ * @return array
+ * @throws AppConfigUnknownKeyException if config key is not known in database
+ * @since 29.0.0
+ */
+ public function getDetails(string $app, string $key): array;
+
+ /**
+ * Convert string like 'string', 'integer', 'float', 'bool' or 'array' to
+ * to bitflag {@see VALUE_STRING}, {@see VALUE_INT}, {@see VALUE_FLOAT},
+ * {@see VALUE_BOOL} and {@see VALUE_ARRAY}
+ *
+ * @param string $type
+ *
+ * @return int
+ * @since 29.0.0
+ */
+ public function convertTypeToInt(string $type): int;
+
+ /**
+ * Convert bitflag {@see VALUE_STRING}, {@see VALUE_INT}, {@see VALUE_FLOAT},
+ * {@see VALUE_BOOL} and {@see VALUE_ARRAY} to human-readable string
+ *
+ * @param int $type
+ *
+ * @return string
+ * @since 29.0.0
+ */
+ public function convertTypeToString(int $type): string;
+
+ /**
+ * Delete single config key from database.
+ *
+ * @param string $app id of the app
+ * @param string $key config key
+ * @since 29.0.0
+ */
+ public function deleteKey(string $app, string $key): void;
+
+ /**
+ * delete all config keys linked to an app
+ *
+ * @param string $app id of the app
+ * @since 29.0.0
+ */
+ public function deleteApp(string $app): void;
+
+ /**
+ * Clear the cache.
+ *
+ * The cache will be rebuilt only the next time a config value is requested.
+ *
+ * @param bool $reload set to TRUE to refill cache instantly after clearing it
+ * @since 29.0.0
+ */
+ public function clearCache(bool $reload = false): void;
/**
* get multiply values, either the app or key can be used as wildcard by setting it to false
*
* @param string|false $key
* @param string|false $app
+ *
* @return array|false
* @since 7.0.0
+ * @deprecated 29.0.0 Use {@see getAllValues()} or {@see searchValues()}
*/
public function getValues($app, $key);
@@ -55,18 +516,10 @@ interface IAppConfig {
* get all values of the app or and filters out sensitive data
*
* @param string $app
+ *
* @return array
* @since 12.0.0
+ * @deprecated 29.0.0 Use {@see getAllValues()} or {@see searchValues()}
*/
public function getFilteredValues($app);
-
- /**
- * Get all apps using the config
- * @return string[] an array of app ids
- *
- * This function returns a list of all apps that have at least one
- * entry in the appconfig table.
- * @since 7.0.0
- */
- public function getApps();
}
diff --git a/lib/public/ICacheFactory.php b/lib/public/ICacheFactory.php
index d70a836aa52..70ad955849d 100644
--- a/lib/public/ICacheFactory.php
+++ b/lib/public/ICacheFactory.php
@@ -75,4 +75,20 @@ interface ICacheFactory {
* @since 13.0.0
*/
public function createLocal(string $prefix = ''): ICache;
+
+ /**
+ * Create an in-memory cache instance
+ *
+ * Useful for remembering values inside one process. Cache memory is cleared
+ * when the object is garbage-collected. Implementation may also expire keys
+ * earlier when the TTL is reached or too much memory is consumed.
+ *
+ * Cache keys are local to the cache object. When building two in-memory
+ * caches, there is no data exchange between the instances.
+ *
+ * @param int $capacity maximum number of cache keys
+ * @return ICache
+ * @since 28.0.0
+ */
+ public function createInMemory(int $capacity = 512): ICache;
}
diff --git a/lib/public/IConfig.php b/lib/public/IConfig.php
index 0e7a7523218..706e4776221 100644
--- a/lib/public/IConfig.php
+++ b/lib/public/IConfig.php
@@ -126,6 +126,7 @@ interface IConfig {
* @param string $appName the appName that we stored the value under
* @return string[] the keys stored for the app
* @since 8.0.0
+ * @deprecated 29.0.0 Use {@see IAppConfig} directly
*/
public function getAppKeys($appName);
@@ -137,6 +138,7 @@ interface IConfig {
* @param string $value the value that should be stored
* @return void
* @since 6.0.0
+ * @deprecated 29.0.0 Use {@see IAppConfig} directly
*/
public function setAppValue($appName, $key, $value);
@@ -146,8 +148,10 @@ interface IConfig {
* @param string $appName the appName that we stored the value under
* @param string $key the key of the value, under which it was saved
* @param string $default the default value to be returned if the value isn't set
+ *
* @return string the saved value
* @since 6.0.0 - parameter $default was added in 7.0.0
+ * @deprecated 29.0.0 Use {@see IAppConfig} directly
*/
public function getAppValue($appName, $key, $default = '');
@@ -157,6 +161,7 @@ interface IConfig {
* @param string $appName the appName that we stored the value under
* @param string $key the key of the value, under which it was saved
* @since 8.0.0
+ * @deprecated 29.0.0 Use {@see IAppConfig} directly
*/
public function deleteAppValue($appName, $key);
@@ -165,6 +170,7 @@ interface IConfig {
*
* @param string $appName the appName the configs are stored under
* @since 8.0.0
+ * @deprecated 29.0.0 Use {@see IAppConfig} directly
*/
public function deleteAppValues($appName);
diff --git a/lib/public/IDBConnection.php b/lib/public/IDBConnection.php
index fe0267facc5..5613aa3743b 100644
--- a/lib/public/IDBConnection.php
+++ b/lib/public/IDBConnection.php
@@ -46,6 +46,26 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
*/
interface IDBConnection {
/**
+ * @since 28.0.0
+ */
+ public const PLATFORM_MYSQL = 'mysql';
+
+ /**
+ * @since 28.0.0
+ */
+ public const PLATFORM_ORACLE = 'oracle';
+
+ /**
+ * @since 28.0.0
+ */
+ public const PLATFORM_POSTGRES = 'postgres';
+
+ /**
+ * @since 28.0.0
+ */
+ public const PLATFORM_SQLITE = 'sqlite';
+
+ /**
* Gets the QueryBuilder for the connection.
*
* @return \OCP\DB\QueryBuilder\IQueryBuilder
@@ -339,4 +359,12 @@ interface IDBConnection {
* @since 13.0.0
*/
public function migrateToSchema(Schema $toSchema): void;
+
+ /**
+ * Returns the database provider name
+ * @link https://github.com/nextcloud/server/issues/30877
+ * @since 28.0.0
+ * @return IDBConnection::PLATFORM_*
+ */
+ public function getDatabaseProvider(): string;
}
diff --git a/lib/public/IGroup.php b/lib/public/IGroup.php
index ec26cc55b69..51417641e26 100644
--- a/lib/public/IGroup.php
+++ b/lib/public/IGroup.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
@@ -38,7 +41,7 @@ interface IGroup {
* @return string
* @since 8.0.0
*/
- public function getGID();
+ public function getGID(): string;
/**
* Returns the group display name
@@ -46,7 +49,7 @@ interface IGroup {
* @return string
* @since 12.0.0
*/
- public function getDisplayName();
+ public function getDisplayName(): string;
/**
* Set the group display name
@@ -60,43 +63,47 @@ interface IGroup {
/**
* get all users in the group
*
- * @return \OCP\IUser[]
+ * @return IUser[]
* @since 8.0.0
*/
- public function getUsers();
+ public function getUsers(): array;
/**
* check if a user is in the group
*
- * @param \OCP\IUser $user
+ * @param IUser $user
+ *
* @return bool
* @since 8.0.0
*/
- public function inGroup(IUser $user);
+ public function inGroup(IUser $user): bool;
/**
* add a user to the group
*
- * @param \OCP\IUser $user
+ * @param IUser $user
+ *
* @since 8.0.0
*/
- public function addUser(IUser $user);
+ public function addUser(IUser $user): void;
/**
- * remove a user from the group
+ * Remove a user from the group
+ *
+ * @param IUser $user
*
- * @param \OCP\IUser $user
* @since 8.0.0
*/
- public function removeUser($user);
+ public function removeUser(IUser $user): void;
/**
* search for users in the group by userid
*
* @param string $search
- * @param int $limit
- * @param int $offset
- * @return \OCP\IUser[]
+ * @param int|null $limit
+ * @param int|null $offset
+ *
+ * @return IUser[]
* @since 8.0.0
*/
public function searchUsers(string $search, ?int $limit = null, ?int $offset = null): array;
@@ -108,7 +115,7 @@ interface IGroup {
* @return int|bool
* @since 8.0.0
*/
- public function count($search = '');
+ public function count(string $search = ''): int|bool;
/**
* returns the number of disabled users
@@ -116,18 +123,19 @@ interface IGroup {
* @return int|bool
* @since 14.0.0
*/
- public function countDisabled();
+ public function countDisabled(): int|bool;
/**
- * search for users in the group by displayname
+ * Search for users in the group by displayname
*
* @param string $search
- * @param int $limit
- * @param int $offset
- * @return \OCP\IUser[]
+ * @param int|null $limit
+ * @param int|null $offset
+ *
+ * @return IUser[]
* @since 8.0.0
*/
- public function searchDisplayName($search, $limit = null, $offset = null);
+ public function searchDisplayName(string $search, int $limit = null, int $offset = null): array;
/**
* Get the names of the backends the group is connected to
@@ -135,27 +143,27 @@ interface IGroup {
* @return string[]
* @since 22.0.0
*/
- public function getBackendNames();
+ public function getBackendNames(): array;
/**
- * delete the group
+ * Delete the group
*
* @return bool
* @since 8.0.0
*/
- public function delete();
+ public function delete(): bool;
/**
* @return bool
* @since 14.0.0
*/
- public function canRemoveUser();
+ public function canRemoveUser(): bool;
/**
* @return bool
* @since 14.0.0
*/
- public function canAddUser();
+ public function canAddUser(): bool;
/**
* @return bool
diff --git a/lib/public/IMemcacheTTL.php b/lib/public/IMemcacheTTL.php
index 8424e5b2bfa..250e727308b 100644
--- a/lib/public/IMemcacheTTL.php
+++ b/lib/public/IMemcacheTTL.php
@@ -35,5 +35,22 @@ interface IMemcacheTTL extends IMemcache {
* @param int $ttl time to live in seconds
* @since 8.2.2
*/
- public function setTTL($key, $ttl);
+ public function setTTL(string $key, int $ttl);
+
+ /**
+ * Get the ttl for an existing value, in seconds till expiry
+ *
+ * @return int|false
+ * @since 27
+ */
+ public function getTTL(string $key): int|false;
+ /**
+ * Set the ttl for an existing value if the value matches
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $ttl time to live in seconds
+ * @since 27
+ */
+ public function compareSetTTL(string $key, $value, int $ttl): bool;
}
diff --git a/lib/public/INavigationManager.php b/lib/public/INavigationManager.php
index 710cbd1248d..36f80c3293f 100644
--- a/lib/public/INavigationManager.php
+++ b/lib/public/INavigationManager.php
@@ -33,6 +33,10 @@
namespace OCP;
/**
+ * @psalm-type NavigationEntry = array{id: string, order: int, href: string, name: string, app?: string, icon?: string, classes?: string, type?: string}
+ */
+
+/**
* Manages the ownCloud navigation
* @since 6.0.0
*/
@@ -58,9 +62,11 @@ interface INavigationManager {
/**
* Creates a new navigation entry
*
- * @param array|\Closure $entry Array containing: id, name, order, icon and href key
+ * @param array array|\Closure $entry Array containing: id, name, order, icon and href key
+ * If a menu entry (type = 'link') is added, you shall also set app to the app that added the entry.
* The use of a closure is preferred, because it will avoid
* loading the routing of your app, unless required.
+ * @psalm-param NavigationEntry|callable():NavigationEntry $entry
* @return void
* @since 6.0.0
*/
diff --git a/lib/public/IPhoneNumberUtil.php b/lib/public/IPhoneNumberUtil.php
new file mode 100644
index 00000000000..733de0e35a6
--- /dev/null
+++ b/lib/public/IPhoneNumberUtil.php
@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+/**
+ *
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP;
+
+/**
+ * @since 28.0.0
+ */
+interface IPhoneNumberUtil {
+ /**
+ * Returns the country code for a specific region
+ *
+ * For example, this would be `41` for Switzerland and `49` for Germany.
+ * Returns null when the region is invalid.
+ *
+ * @param string $regionCode Two-letter region code of ISO 3166-1
+ * @return int|null Null when invalid/unsupported, the phone country code otherwise
+ * @since 28.0.0
+ */
+ public function getCountryCodeForRegion(string $regionCode): ?int;
+
+ /**
+ * Converts a given input into an E164 formatted phone number
+ *
+ * E164 is the international format without any formatting characters or spaces.
+ * E.g. +41446681800 where +41 is the region code.
+ *
+ * @param string $input Input phone number can contain formatting spaces, slashes and dashes
+ * @param string|null $defaultRegion Two-letter region code of ISO 3166-1
+ * @return string|null Null when the input is invalid for the given region or requires a region.
+ * @since 28.0.0
+ */
+ public function convertToStandardFormat(string $input, ?string $defaultRegion = null): ?string;
+}
diff --git a/lib/public/IPreview.php b/lib/public/IPreview.php
index 2758eba8d63..d8e17b5b029 100644
--- a/lib/public/IPreview.php
+++ b/lib/public/IPreview.php
@@ -38,7 +38,14 @@ use OCP\Files\SimpleFS\ISimpleFile;
* @since 6.0.0
*/
interface IPreview {
+ /**
+ * @since 11.0.0
+ */
public const MODE_FILL = 'fill';
+
+ /**
+ * @since 11.0.0
+ */
public const MODE_COVER = 'cover';
/**
diff --git a/lib/public/IURLGenerator.php b/lib/public/IURLGenerator.php
index 8229d51f231..396867e22b3 100644
--- a/lib/public/IURLGenerator.php
+++ b/lib/public/IURLGenerator.php
@@ -41,6 +41,7 @@ interface IURLGenerator {
* This is a copy of the frontend regex in core/src/OCP/comments.js, make sure to adjust both when changing
*
* @since 25.0.0
+ * @since 29.0.0 changed to match localhost and hostnames with ports
*/
public const URL_REGEX = '/' . self::URL_REGEX_NO_MODIFIERS . '/mi';
@@ -50,8 +51,9 @@ interface IURLGenerator {
* This is a copy of the frontend regex in core/src/OCP/comments.js, make sure to adjust both when changing
*
* @since 25.0.0
+ * @since 29.0.0 changed to match localhost and hostnames with ports
*/
- public const URL_REGEX_NO_MODIFIERS = '(\s|\n|^)(https?:\/\/)((?:[-A-Z0-9+_]+\.)+[-A-Z]+(?:\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)(\s|\n|$)';
+ public const URL_REGEX_NO_MODIFIERS = '(\s|\n|^)(https?:\/\/)([-A-Z0-9+_.]+(?::[0-9]+)?(?:\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)(\s|\n|$)';
/**
* Returns the URL for a route
@@ -95,6 +97,7 @@ interface IURLGenerator {
* @param string $appName the name of the app
* @param string $file the name of the file
* @return string the url
+ * @throws \RuntimeException If the image does not exist
* @since 6.0.0
*/
public function imagePath(string $appName, string $file): string;
diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php
index 1efb3d5f0c2..0a94c5ad928 100644
--- a/lib/public/IUserManager.php
+++ b/lib/public/IUserManager.php
@@ -140,6 +140,12 @@ interface IUserManager {
public function searchDisplayName($pattern, $limit = null, $offset = null);
/**
+ * @return IUser[]
+ * @since 28.0.0
+ */
+ public function getDisabledUsers(?int $limit = null, int $offset = 0): array;
+
+ /**
* Search known users (from phonebook sync) by displayName
*
* @param string $searcher
diff --git a/lib/public/Log/Audit/CriticalActionPerformedEvent.php b/lib/public/Log/Audit/CriticalActionPerformedEvent.php
index 79c67e5b8bd..45786a5c980 100644
--- a/lib/public/Log/Audit/CriticalActionPerformedEvent.php
+++ b/lib/public/Log/Audit/CriticalActionPerformedEvent.php
@@ -49,8 +49,8 @@ class CriticalActionPerformedEvent extends Event {
* @since 22.0.0
*/
public function __construct(string $logMessage,
- array $parameters = [],
- bool $obfuscateParameters = false) {
+ array $parameters = [],
+ bool $obfuscateParameters = false) {
parent::__construct();
$this->logMessage = $logMessage;
$this->parameters = $parameters;
diff --git a/lib/public/Log/ILogFactory.php b/lib/public/Log/ILogFactory.php
index e0128d6b11c..e51a674afbd 100644
--- a/lib/public/Log/ILogFactory.php
+++ b/lib/public/Log/ILogFactory.php
@@ -24,7 +24,6 @@
*/
namespace OCP\Log;
-use OCP\ILogger;
use Psr\Log\LoggerInterface;
/**
@@ -42,15 +41,6 @@ interface ILogFactory {
/**
* @param string $path
- * @return ILogger
- * @since 14.0.0
- * @deprecated 22.0.0 Use \OCP\Log\ILogFactory::getCustomPsrLogger
- * @see \OCP\Log\ILogFactory::getCustomPsrLogger
- */
- public function getCustomLogger(string $path): ILogger;
-
- /**
- * @param string $path
* @param string $type
* @param string $tag
* @return LoggerInterface
diff --git a/lib/public/Migration/IOutput.php b/lib/public/Migration/IOutput.php
index 70fb56b6bdd..97b0e15b9b5 100644
--- a/lib/public/Migration/IOutput.php
+++ b/lib/public/Migration/IOutput.php
@@ -32,6 +32,13 @@ interface IOutput {
/**
* @param string $message
* @return void
+ * @since 28.0.0
+ */
+ public function debug(string $message): void;
+
+ /**
+ * @param string $message
+ * @return void
* @since 9.1.0
*/
public function info($message);
diff --git a/lib/public/OCM/Events/ResourceTypeRegisterEvent.php b/lib/public/OCM/Events/ResourceTypeRegisterEvent.php
new file mode 100644
index 00000000000..1048d8d0d49
--- /dev/null
+++ b/lib/public/OCM/Events/ResourceTypeRegisterEvent.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+/*
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\OCM\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\OCM\IOCMProvider;
+
+/**
+ * Use this event to register additional OCM resources before the API returns
+ * them in the OCM provider list and capability
+ *
+ * @since 28.0.0
+ */
+class ResourceTypeRegisterEvent extends Event {
+ /**
+ * @param IOCMProvider $provider
+ * @since 28.0.0
+ */
+ public function __construct(
+ protected IOCMProvider $provider,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @param string $name
+ * @param list<string> $shareTypes List of supported share recipients, e.g. 'user', 'group', …
+ * @param array<string, string> $protocols List of supported protocols and their location,
+ * e.g. ['webdav' => '/remote.php/webdav/']
+ * @since 28.0.0
+ */
+ public function registerResourceType(string $name, array $shareTypes, array $protocols): void {
+ $resourceType = $this->provider->createNewResourceType();
+ $resourceType->setName($name)
+ ->setShareTypes($shareTypes)
+ ->setProtocols($protocols);
+ $this->provider->addResourceType($resourceType);
+ }
+}
diff --git a/lib/public/OCM/Exceptions/OCMArgumentException.php b/lib/public/OCM/Exceptions/OCMArgumentException.php
new file mode 100644
index 00000000000..e3abd7bf26b
--- /dev/null
+++ b/lib/public/OCM/Exceptions/OCMArgumentException.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023, Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\OCM\Exceptions;
+
+use Exception;
+
+/**
+ * @since 28.0.0
+ */
+class OCMArgumentException extends Exception {
+}
diff --git a/lib/public/OCM/Exceptions/OCMProviderException.php b/lib/public/OCM/Exceptions/OCMProviderException.php
new file mode 100644
index 00000000000..32dab10dc68
--- /dev/null
+++ b/lib/public/OCM/Exceptions/OCMProviderException.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023, Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\OCM\Exceptions;
+
+use Exception;
+
+/**
+ * @since 28.0.0
+ */
+class OCMProviderException extends Exception {
+}
diff --git a/lib/public/OCM/IOCMDiscoveryService.php b/lib/public/OCM/IOCMDiscoveryService.php
new file mode 100644
index 00000000000..2407e7b24e8
--- /dev/null
+++ b/lib/public/OCM/IOCMDiscoveryService.php
@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\OCM;
+
+use OCP\OCM\Exceptions\OCMProviderException;
+
+/**
+ * Discover remote OCM services
+ *
+ * @since 28.0.0
+ */
+interface IOCMDiscoveryService {
+ /**
+ * Discover remote OCM services
+ *
+ * @param string $remote address of the remote provider
+ * @param bool $skipCache ignore cache, refresh data
+ *
+ * @return IOCMProvider
+ * @throws OCMProviderException if no valid discovery data can be returned
+ * @since 28.0.0
+ */
+ public function discover(string $remote, bool $skipCache = false): IOCMProvider;
+}
diff --git a/lib/public/OCM/IOCMProvider.php b/lib/public/OCM/IOCMProvider.php
new file mode 100644
index 00000000000..6df7eed370c
--- /dev/null
+++ b/lib/public/OCM/IOCMProvider.php
@@ -0,0 +1,165 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\OCM;
+
+use JsonSerializable;
+use OCP\OCM\Exceptions\OCMArgumentException;
+use OCP\OCM\Exceptions\OCMProviderException;
+
+/**
+ * Model based on the Open Cloud Mesh Discovery API
+ * @link https://github.com/cs3org/OCM-API/
+ * @since 28.0.0
+ */
+interface IOCMProvider extends JsonSerializable {
+ /**
+ * enable OCM
+ *
+ * @param bool $enabled
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setEnabled(bool $enabled): static;
+
+ /**
+ * is set as enabled ?
+ *
+ * @return bool
+ * @since 28.0.0
+ */
+ public function isEnabled(): bool;
+
+ /**
+ * get set API Version
+ *
+ * @param string $apiVersion
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setApiVersion(string $apiVersion): static;
+
+ /**
+ * returns API version
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getApiVersion(): string;
+
+ /**
+ * configure endpoint
+ *
+ * @param string $endPoint
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setEndPoint(string $endPoint): static;
+
+ /**
+ * get configured endpoint
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getEndPoint(): string;
+
+ /**
+ * create a new resource to later add it with {@see addResourceType()}
+ * @return IOCMResource
+ * @since 28.0.0
+ */
+ public function createNewResourceType(): IOCMResource;
+
+ /**
+ * add a single resource to the object
+ *
+ * @param IOCMResource $resource
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function addResourceType(IOCMResource $resource): static;
+
+ /**
+ * set resources
+ *
+ * @param IOCMResource[] $resourceTypes
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setResourceTypes(array $resourceTypes): static;
+
+ /**
+ * get all set resources
+ *
+ * @return IOCMResource[]
+ * @since 28.0.0
+ */
+ public function getResourceTypes(): array;
+
+ /**
+ * extract a specific string value from the listing of protocols, based on resource-name and protocol-name
+ *
+ * @param string $resourceName
+ * @param string $protocol
+ *
+ * @return string
+ * @throws OCMArgumentException
+ * @since 28.0.0
+ */
+ public function extractProtocolEntry(string $resourceName, string $protocol): string;
+
+ /**
+ * import data from an array
+ *
+ * @param array<string, int|string|bool|array> $data
+ *
+ * @return $this
+ * @throws OCMProviderException in case a descent provider cannot be generated from data
+ * @since 28.0.0
+ */
+ public function import(array $data): static;
+
+ /**
+ * @return array{
+ * enabled: bool,
+ * apiVersion: string,
+ * endPoint: string,
+ * resourceTypes: array{
+ * name: string,
+ * shareTypes: string[],
+ * protocols: array<string, string>
+ * }[]
+ * }
+ * @since 28.0.0
+ */
+ public function jsonSerialize(): array;
+}
diff --git a/lib/public/OCM/IOCMResource.php b/lib/public/OCM/IOCMResource.php
new file mode 100644
index 00000000000..242c77116f1
--- /dev/null
+++ b/lib/public/OCM/IOCMResource.php
@@ -0,0 +1,111 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\OCM;
+
+use JsonSerializable;
+
+/**
+ * Model based on the Open Cloud Mesh Discovery API
+ *
+ * @link https://github.com/cs3org/OCM-API/
+ * @since 28.0.0
+ */
+interface IOCMResource extends JsonSerializable {
+ /**
+ * set name of the resource
+ *
+ * @param string $name
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setName(string $name): static;
+
+ /**
+ * get name of the resource
+ *
+ * @return string
+ * @since 28.0.0
+ */
+ public function getName(): string;
+
+ /**
+ * set share types
+ *
+ * @param string[] $shareTypes
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setShareTypes(array $shareTypes): static;
+
+ /**
+ * get share types
+ *
+ * @return string[]
+ * @since 28.0.0
+ */
+ public function getShareTypes(): array;
+
+ /**
+ * set available protocols
+ *
+ * @param array<string, string> $protocols
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function setProtocols(array $protocols): static;
+
+ /**
+ * get configured protocols
+ *
+ * @return array<string, string>
+ * @since 28.0.0
+ */
+ public function getProtocols(): array;
+
+ /**
+ * import data from an array
+ *
+ * @param array $data
+ *
+ * @return $this
+ * @since 28.0.0
+ */
+ public function import(array $data): static;
+
+ /**
+ * @return array{
+ * name: string,
+ * shareTypes: string[],
+ * protocols: array<string, string>
+ * }
+ * @since 28.0.0
+ */
+ public function jsonSerialize(): array;
+}
diff --git a/lib/public/Profile/IProfileManager.php b/lib/public/Profile/IProfileManager.php
new file mode 100644
index 00000000000..996e49d116e
--- /dev/null
+++ b/lib/public/Profile/IProfileManager.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Profile;
+
+use OCP\Accounts\IAccountManager;
+use OCP\IUser;
+
+/**
+ * @since 28.0.0
+ */
+interface IProfileManager {
+ /**
+ * Visible to users, guests, and public access
+ *
+ * @since 28.0.0
+ */
+ public const VISIBILITY_SHOW = 'show';
+
+ /**
+ * Visible to users and guests
+ *
+ * @since 28.0.0
+ */
+ public const VISIBILITY_SHOW_USERS_ONLY = 'show_users_only';
+
+ /**
+ * Visible to nobody
+ *
+ * @since 28.0.0
+ */
+ public const VISIBILITY_HIDE = 'hide';
+
+ /**
+ * Default account property visibility
+ *
+ * @since 28.0.0
+ */
+ public const DEFAULT_PROPERTY_VISIBILITY = [
+ IAccountManager::PROPERTY_ADDRESS => self::VISIBILITY_SHOW_USERS_ONLY,
+ IAccountManager::PROPERTY_AVATAR => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_BIOGRAPHY => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_DISPLAYNAME => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_HEADLINE => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_ORGANISATION => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_ROLE => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_EMAIL => self::VISIBILITY_SHOW_USERS_ONLY,
+ IAccountManager::PROPERTY_PHONE => self::VISIBILITY_SHOW_USERS_ONLY,
+ IAccountManager::PROPERTY_TWITTER => self::VISIBILITY_SHOW,
+ IAccountManager::PROPERTY_WEBSITE => self::VISIBILITY_SHOW,
+ ];
+
+ /**
+ * Default visibility
+ *
+ * @since 28.0.0
+ */
+ public const DEFAULT_VISIBILITY = self::VISIBILITY_SHOW_USERS_ONLY;
+
+ /**
+ * If no user is passed as an argument return whether profile is enabled globally in `config.php`
+ *
+ * @since 28.0.0
+ */
+ public function isProfileEnabled(?IUser $user = null): bool;
+
+ /**
+ * Return whether the profile parameter of the target user
+ * is visible to the visiting user
+ *
+ * @since 28.0.0
+ */
+ public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool;
+
+ /**
+ * Return the profile parameters of the target user that are visible to the visiting user
+ * in an associative array
+ *
+ * @return array{userId: string, address?: ?string, biography?: ?string, displayname?: ?string, headline?: ?string, isUserAvatarVisible?: bool, organisation?: ?string, role?: ?string, actions: list<array{id: string, icon: string, title: string, target: ?string}>}
+ * @since 28.0.0
+ */
+ public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array;
+}
diff --git a/lib/public/Search/FilterDefinition.php b/lib/public/Search/FilterDefinition.php
new file mode 100644
index 00000000000..c1e23cd3cd3
--- /dev/null
+++ b/lib/public/Search/FilterDefinition.php
@@ -0,0 +1,136 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Search;
+
+use InvalidArgumentException;
+
+/**
+ * Filter definition
+ *
+ * Describe filter attributes
+ *
+ * @since 28.0.0
+ */
+class FilterDefinition {
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_BOOL = 'bool';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_INT = 'int';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_FLOAT = 'float';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_STRING = 'string';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_STRINGS = 'strings';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_DATETIME = 'datetime';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_PERSON = 'person';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_NC_USER = 'nc-user';
+
+ /**
+ * @since 28.0.0
+ */
+ public const TYPE_NC_GROUP = 'nc-group';
+
+ /**
+ * Build filter definition
+ *
+ * @param self::TYPE_* $type
+ * @param bool $exclusive If true, all providers not supporting this filter will be ignored when this filter is provided
+ * @throw InvalidArgumentException in case of invalid name. Allowed characters are -, 0-9, a-z.
+ * @since 28.0.0
+ */
+ public function __construct(
+ private string $name,
+ private string $type = self::TYPE_STRING,
+ private bool $exclusive = true,
+ ) {
+ if (!preg_match('/[-0-9a-z]+/Au', $name)) {
+ throw new InvalidArgumentException('Invalid filter name. Allowed characters are [-0-9a-z]');
+ }
+ }
+
+ /**
+ * Filter name
+ *
+ * Name is used in query string and for advanced syntax `name: <value>`
+ *
+ * @since 28.0.0
+ */
+ public function name(): string {
+ return $this->name;
+ }
+
+ /**
+ * Filter type
+ *
+ * Expected type of value for the filter
+ *
+ * @return self::TYPE_*
+ * @since 28.0.0
+ */
+ public function type(): string {
+ return $this->type;
+ }
+
+ /**
+ * Is filter exclusive?
+ *
+ * If exclusive, only provider with support for this filter will receive the query.
+ * Example: if an exclusive filter `mimetype` is declared, a search with this term will not
+ * be send to providers like `settings` that doesn't support it.
+ *
+ * @since 28.0.0
+ */
+ public function exclusive(): bool {
+ return $this->exclusive;
+ }
+}
diff --git a/lib/public/Search/IFilter.php b/lib/public/Search/IFilter.php
new file mode 100644
index 00000000000..6065622cb71
--- /dev/null
+++ b/lib/public/Search/IFilter.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Search;
+
+/**
+ * Interface for search filters
+ *
+ * @since 28.0.0
+ */
+interface IFilter {
+ /** @since 28.0.0 */
+ public const BUILTIN_TERM = 'term';
+ /** @since 28.0.0 */
+ public const BUILTIN_SINCE = 'since';
+ /** @since 28.0.0 */
+ public const BUILTIN_UNTIL = 'until';
+ /** @since 28.0.0 */
+ public const BUILTIN_PERSON = 'person';
+ /** @since 28.0.0 */
+ public const BUILTIN_TITLE_ONLY = 'title-only';
+ /** @since 28.0.0 */
+ public const BUILTIN_PLACES = 'places';
+ /** @since 28.0.0 */
+ public const BUILTIN_PROVIDER = 'provider';
+
+ /**
+ * Get filter value
+ *
+ * @since 28.0.0
+ */
+ public function get(): mixed;
+}
diff --git a/lib/public/Search/IFilterCollection.php b/lib/public/Search/IFilterCollection.php
new file mode 100644
index 00000000000..6ca53a1c628
--- /dev/null
+++ b/lib/public/Search/IFilterCollection.php
@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Search;
+
+use IteratorAggregate;
+
+/**
+ * Interface for search filters
+ *
+ * @since 28.0.0
+ * @extends IteratorAggregate<string, \OCP\Search\IFilter>
+ */
+interface IFilterCollection extends IteratorAggregate {
+ /**
+ * Check if a filter exits
+ *
+ * @since 28.0.0
+ */
+ public function has(string $name): bool;
+
+ /**
+ * Get a filter by name
+ *
+ * @since 28.0.0
+ */
+ public function get(string $name): ?IFilter;
+
+ /**
+ * Return Iterator of filters
+ *
+ * @since 28.0.0
+ */
+ public function getIterator(): \Traversable;
+}
diff --git a/lib/public/Search/IFilteringProvider.php b/lib/public/Search/IFilteringProvider.php
new file mode 100644
index 00000000000..dbe1044a539
--- /dev/null
+++ b/lib/public/Search/IFilteringProvider.php
@@ -0,0 +1,72 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Search;
+
+/**
+ * Interface for advanced search providers
+ *
+ * These providers will be implemented in apps, so they can participate in the
+ * global search results of Nextcloud. If an app provides more than one type of
+ * resource, e.g. contacts and address books in Nextcloud Contacts, it should
+ * register one provider per group.
+ *
+ * @since 28.0.0
+ */
+interface IFilteringProvider extends IProvider {
+ /**
+ * Return the names of filters supported by the application
+ *
+ * If a filter sent by client is not in this list,
+ * the current provider will be ignored.
+ * Example:
+ * array('term', 'since', 'custom-filter');
+ *
+ * @since 28.0.0
+ * @return string[] Name of supported filters (default or defined by application)
+ */
+ public function getSupportedFilters(): array;
+
+ /**
+ * Get alternate IDs handled by this provider
+ *
+ * A search provider can complete results from other search providers.
+ * For example, files and full-text-search can search in files.
+ * If you use `in:files` in a search, provider files will be invoked,
+ * with all other providers declaring `files` in this method
+ *
+ * @since 28.0.0
+ * @return string[] IDs
+ */
+ public function getAlternateIds(): array;
+
+ /**
+ * Allows application to declare custom filters
+ *
+ * @since 28.0.0
+ * @return list<FilterDefinition>
+ */
+ public function getCustomFilters(): array;
+}
diff --git a/lib/public/Search/IInAppSearch.php b/lib/public/Search/IInAppSearch.php
new file mode 100644
index 00000000000..9e1e294bf4d
--- /dev/null
+++ b/lib/public/Search/IInAppSearch.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @author Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCP\Search;
+
+/**
+ * Interface for search providers supporting in-app search
+ *
+ * @since 28.0.0
+ */
+interface IInAppSearch extends IProvider {
+}
diff --git a/lib/public/Search/IProvider.php b/lib/public/Search/IProvider.php
index 61655c47367..95d7a1b163a 100644
--- a/lib/public/Search/IProvider.php
+++ b/lib/public/Search/IProvider.php
@@ -68,15 +68,17 @@ interface IProvider {
/**
* Get the search provider order
* The lower the int, the higher it will be sorted (0 will be before 10)
+ * If null, the search provider will be hidden in the UI and the API not called
*
* @param string $route the route the user is currently at, e.g. files.view.index
* @param array $routeParameters the parameters of the route the user is currently at, e.g. [fileId = 982, dir = "/"]
*
- * @return int
+ * @return int|null
*
* @since 20.0.0
+ * @since 28.0.0 Can return null
*/
- public function getOrder(string $route, array $routeParameters): int;
+ public function getOrder(string $route, array $routeParameters): ?int;
/**
* Find matching search entries in an app
diff --git a/lib/public/Search/ISearchQuery.php b/lib/public/Search/ISearchQuery.php
index a545d1dbccb..75d95b45c4c 100644
--- a/lib/public/Search/ISearchQuery.php
+++ b/lib/public/Search/ISearchQuery.php
@@ -52,6 +52,20 @@ interface ISearchQuery {
public function getTerm(): string;
/**
+ * Get a single request filter
+ *
+ * @since 28.0.0
+ */
+ public function getFilter(string $name): ?IFilter;
+
+ /**
+ * Get request filters
+ *
+ * @since 28.0.0
+ */
+ public function getFilters(): IFilterCollection;
+
+ /**
* Get the sort order of results as defined as SORT_* constants on this interface
*
* @return int
diff --git a/lib/public/Search/SearchResult.php b/lib/public/Search/SearchResult.php
index 9ac8b28fb8b..892c60777b3 100644
--- a/lib/public/Search/SearchResult.php
+++ b/lib/public/Search/SearchResult.php
@@ -54,9 +54,9 @@ final class SearchResult implements JsonSerializable {
* @since 20.0.0
*/
private function __construct(string $name,
- bool $isPaginated,
- array $entries,
- $cursor = null) {
+ bool $isPaginated,
+ array $entries,
+ $cursor = null) {
$this->name = $name;
$this->isPaginated = $isPaginated;
$this->entries = $entries;
@@ -87,8 +87,8 @@ final class SearchResult implements JsonSerializable {
* @since 20.0.0
*/
public static function paginated(string $name,
- array $entries,
- $cursor): self {
+ array $entries,
+ $cursor): self {
return new self(
$name,
true,
diff --git a/lib/public/Search/SearchResultEntry.php b/lib/public/Search/SearchResultEntry.php
index 86a3f08cfe6..f4ff1ec2a5c 100644
--- a/lib/public/Search/SearchResultEntry.php
+++ b/lib/public/Search/SearchResultEntry.php
@@ -98,11 +98,11 @@ class SearchResultEntry implements JsonSerializable {
* @since 20.0.0
*/
public function __construct(string $thumbnailUrl,
- string $title,
- string $subline,
- string $resourceUrl,
- string $icon = '',
- bool $rounded = false) {
+ string $title,
+ string $subline,
+ string $resourceUrl,
+ string $icon = '',
+ bool $rounded = false) {
$this->thumbnailUrl = $thumbnailUrl;
$this->title = $title;
$this->subline = $subline;
diff --git a/lib/public/Security/ISecureRandom.php b/lib/public/Security/ISecureRandom.php
index 3634ebf99f7..530befb0257 100644
--- a/lib/public/Security/ISecureRandom.php
+++ b/lib/public/Security/ISecureRandom.php
@@ -41,17 +41,36 @@ namespace OCP\Security;
interface ISecureRandom {
/**
* Flags for characters that can be used for <code>generate($length, $characters)</code>
+ * @since 8.0.0
*/
public const CHAR_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+ /**
+ * @since 8.0.0
+ */
public const CHAR_LOWER = 'abcdefghijklmnopqrstuvwxyz';
+
+ /**
+ * @since 8.0.0
+ */
public const CHAR_DIGITS = '0123456789';
+
+ /**
+ * @since 8.0.0
+ */
public const CHAR_SYMBOLS = '!\"#$%&\\\'()*+,-./:;<=>?@[\]^_`{|}~';
+
+ /**
+ * @since 12.0.0
+ */
public const CHAR_ALPHANUMERIC = self::CHAR_UPPER . self::CHAR_LOWER . self::CHAR_DIGITS;
/**
* Characters that can be used for <code>generate($length, $characters)</code>, to
- * generate human readable random strings. Lower- and upper-case characters and digits
+ * generate human-readable random strings. Lower- and upper-case characters and digits
* are included. Characters which are ambiguous are excluded, such as I, l, and 1 and so on.
+ *
+ * @since 23.0.0
*/
public const CHAR_HUMAN_READABLE = 'abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789';
@@ -64,5 +83,5 @@ interface ISecureRandom {
* @since 8.0.0
*/
public function generate(int $length,
- string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'): string;
+ string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'): string;
}
diff --git a/lib/public/Security/RateLimiting/ILimiter.php b/lib/public/Security/RateLimiting/ILimiter.php
new file mode 100644
index 00000000000..cfc7387664d
--- /dev/null
+++ b/lib/public/Security/RateLimiting/ILimiter.php
@@ -0,0 +1,72 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Security\RateLimiting;
+
+use OCP\AppFramework\Http\Attribute\AnonRateLimit;
+use OCP\AppFramework\Http\Attribute\UserRateLimit;
+use OCP\IUser;
+
+/**
+ * Programmatic rate limiter for web requests that are not handled by an app framework controller
+ *
+ * @see AnonRateLimit
+ * @see UserRateLimit
+ *
+ * @since 28.0.0
+ */
+interface ILimiter {
+ /**
+ * Registers attempt for an anonymous request
+ *
+ * @param string $identifier
+ * @param int $anonLimit
+ * @param int $anonPeriod in seconds
+ * @param string $ip
+ * @throws IRateLimitExceededException if limits are reached, which should cause a HTTP 429 response
+ * @since 28.0.0
+ *
+ */
+ public function registerAnonRequest(string $identifier,
+ int $anonLimit,
+ int $anonPeriod,
+ string $ip): void;
+
+ /**
+ * Registers attempt for an authenticated request
+ *
+ * @param string $identifier
+ * @param int $userLimit
+ * @param int $userPeriod in seconds
+ * @param IUser $user the acting user
+ * @throws IRateLimitExceededException if limits are reached, which should cause a HTTP 429 response
+ * @since 28.0.0
+ *
+ */
+ public function registerUserRequest(string $identifier,
+ int $userLimit,
+ int $userPeriod,
+ IUser $user): void;
+}
diff --git a/lib/public/Security/RateLimiting/IRateLimitExceededException.php b/lib/public/Security/RateLimiting/IRateLimitExceededException.php
new file mode 100644
index 00000000000..9bc8c22a67c
--- /dev/null
+++ b/lib/public/Security/RateLimiting/IRateLimitExceededException.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Security\RateLimiting;
+
+use Throwable;
+
+/**
+ * Thrown if the (anonymous) user has exceeded a rate limit
+ *
+ * @since 28.0.0
+ */
+interface IRateLimitExceededException extends Throwable {
+}
diff --git a/lib/public/Settings/DeclarativeSettingsTypes.php b/lib/public/Settings/DeclarativeSettingsTypes.php
new file mode 100644
index 00000000000..01e20ee7cc9
--- /dev/null
+++ b/lib/public/Settings/DeclarativeSettingsTypes.php
@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Andrey Borysenko <andrey.borysenko@nextcloud.com>
+ *
+ * @author Andrey Borysenko <andrey.borysenko@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Settings;
+
+/**
+ * Declarative settings types supported in the IDeclarativeSettingsForm forms
+ *
+ * @since 29.0.0
+ */
+final class DeclarativeSettingsTypes {
+ /**
+ * IDeclarativeSettingsForm section_type which is determines where the form is displayed
+ *
+ * @since 29.0.0
+ */
+ public const SECTION_TYPE_ADMIN = 'admin';
+
+ /**
+ * IDeclarativeSettingsForm section_type which is determines where the form is displayed
+ *
+ * @since 29.0.0
+ */
+ public const SECTION_TYPE_PERSONAL = 'personal';
+
+ /**
+ * IDeclarativeSettingsForm storage_type which is determines where and how the config value is stored
+ *
+ *
+ * For `external` storage_type the app implementing \OCP\Settings\SetDeclarativeSettingsValueEvent and \OCP\Settings\GetDeclarativeSettingsValueEvent events is responsible for storing and retrieving the config value.
+ *
+ * @since 29.0.0
+ */
+ public const STORAGE_TYPE_EXTERNAL = 'external';
+
+ /**
+ * IDeclarativeSettingsForm storage_type which is determines where and how the config value is stored
+ *
+ * For `internal` storage_type the config value is stored in default `appconfig` and `preferences` tables.
+ * For `external` storage_type the app implementing \OCP\Settings\SetDeclarativeSettingsValueEvent and \OCP\Settings\GetDeclarativeSettingsValueEvent events is responsible for storing and retrieving the config value.
+ *
+ * @since 29.0.0
+ */
+ public const STORAGE_TYPE_INTERNAL = 'internal';
+
+ /**
+ * NcInputField type text
+ *
+ * @since 29.0.0
+ */
+ public const TEXT = 'text';
+
+ /**
+ * NcInputField type password
+ *
+ * @since 29.0.0
+ */
+ public const PASSWORD = 'password';
+
+ /**
+ * NcInputField type email
+ *
+ * @since 29.0.0
+ */
+ public const EMAIL = 'email';
+
+ /**
+ * NcInputField type tel
+ *
+ * @since 29.0.0
+ */
+ public const TEL = 'tel';
+
+ /**
+ * NcInputField type url
+ *
+ * @since 29.0.0
+ */
+ public const URL = 'url';
+
+ /**
+ * NcInputField type number
+ *
+ * @since 29.0.0
+ */
+ public const NUMBER = 'number';
+
+ /**
+ * NcCheckboxRadioSwitch type checkbox
+ *
+ * @since 29.0.0
+ */
+ public const CHECKBOX = 'checkbox';
+
+ /**
+ * Multiple NcCheckboxRadioSwitch type checkbox representing a one config value (saved as JSON object)
+ *
+ * @since 29.0.0
+ */
+ public const MULTI_CHECKBOX = 'multi-checkbox';
+
+ /**
+ * NcCheckboxRadioSwitch type radio
+ *
+ * @since 29.0.0
+ */
+ public const RADIO = 'radio';
+
+ /**
+ * NcSelect
+ *
+ * @since 29.0.0
+ */
+ public const SELECT = 'select';
+
+ /**
+ * Multiple NcSelect representing a one config value (saved as JSON array)
+ *
+ * @since 29.0.0
+ */
+ public const MULTI_SELECT = 'multi-select';
+}
diff --git a/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php b/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php
new file mode 100644
index 00000000000..925bf9fe711
--- /dev/null
+++ b/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Settings\Events;
+
+use Exception;
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+use OCP\Settings\IDeclarativeSettingsForm;
+
+/**
+ * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm
+ *
+ * @since 29.0.0
+ */
+class DeclarativeSettingsGetValueEvent extends Event {
+ /**
+ * @var ?DeclarativeSettingsValueTypes
+ */
+ private mixed $value = null;
+
+ /**
+ * @since 29.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private string $app,
+ private string $formId,
+ private string $fieldId,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getApp(): string {
+ return $this->app;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getFormId(): string {
+ return $this->formId;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getFieldId(): string {
+ return $this->fieldId;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function setValue(mixed $value): void {
+ $this->value = $value;
+ }
+
+ /**
+ * @return DeclarativeSettingsValueTypes
+ * @throws Exception
+ *
+ * @since 29.0.0
+ */
+ public function getValue(): mixed {
+ if ($this->value === null) {
+ throw new Exception('Value not set');
+ }
+
+ return $this->value;
+ }
+}
diff --git a/lib/public/Dashboard/RegisterWidgetEvent.php b/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php
index f0bf049571a..a9ea399fc20 100644
--- a/lib/public/Dashboard/RegisterWidgetEvent.php
+++ b/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php
@@ -3,9 +3,9 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
*
- * @author Julius Härtl <jus@bitgrid.net>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -23,39 +23,31 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-namespace OCP\Dashboard;
+
+namespace OCP\Settings\Events;
use OCP\EventDispatcher\Event;
+use OCP\Settings\IDeclarativeManager;
+use OCP\Settings\IDeclarativeSettingsForm;
/**
- * Class RegisterPanelEvent
- *
- * This event is dispatched to allow apps supporting older Nextcloud versions to
- * still register their dashboard panels so that they are only constructed when
- * they are needed. Deprecated right away so we can drop it again after 19 is EOL
- * and backward compatible apps can use OCP\AppFramework\Bootstrap\IBootstrap
+ * @psalm-import-type DeclarativeSettingsFormSchemaWithoutValues from IDeclarativeSettingsForm
*
- * @since 20.0.0
- * @deprecated 20.0.0
+ * @since 29.0.0
*/
-class RegisterWidgetEvent extends Event {
- private $manager;
-
+class DeclarativeSettingsRegisterFormEvent extends Event {
/**
- * @param IManager $manager
- * @since 20.0.0
+ * @since 29.0.0
*/
- public function __construct(IManager $manager) {
+ public function __construct(private IDeclarativeManager $manager) {
parent::__construct();
-
- $this->manager = $manager;
}
/**
- * @param string $panelClass
- * @since 20.0.0
+ * @param DeclarativeSettingsFormSchemaWithoutValues $schema
+ * @since 29.0.0
*/
- public function registerWidget(string $panelClass) {
- $this->manager->lazyRegisterWidget($panelClass);
+ public function registerSchema(string $app, array $schema): void {
+ $this->manager->registerSchema($app, $schema);
}
}
diff --git a/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php b/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php
new file mode 100644
index 00000000000..f94c17681a8
--- /dev/null
+++ b/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php
@@ -0,0 +1,87 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Settings\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+use OCP\Settings\IDeclarativeSettingsForm;
+
+/**
+ * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm
+ *
+ * @since 29.0.0
+ */
+class DeclarativeSettingsSetValueEvent extends Event {
+ /**
+ * @param DeclarativeSettingsValueTypes $value
+ * @since 29.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private string $app,
+ private string $formId,
+ private string $fieldId,
+ private mixed $value,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getApp(): string {
+ return $this->app;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getFormId(): string {
+ return $this->formId;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getFieldId(): string {
+ return $this->fieldId;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getValue(): mixed {
+ return $this->value;
+ }
+}
diff --git a/lib/public/Settings/IDeclarativeManager.php b/lib/public/Settings/IDeclarativeManager.php
new file mode 100644
index 00000000000..ac5bef6ed26
--- /dev/null
+++ b/lib/public/Settings/IDeclarativeManager.php
@@ -0,0 +1,92 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Settings;
+
+use Exception;
+use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
+use OCP\IUser;
+
+/**
+ * @since 29.0.0
+ *
+ * @psalm-import-type DeclarativeSettingsValueTypes from IDeclarativeSettingsForm
+ * @psalm-import-type DeclarativeSettingsSectionType from IDeclarativeSettingsForm
+ * @psalm-import-type DeclarativeSettingsFormSchemaWithValues from IDeclarativeSettingsForm
+ * @psalm-import-type DeclarativeSettingsFormSchemaWithoutValues from IDeclarativeSettingsForm
+ */
+interface IDeclarativeManager {
+ /**
+ * Registers a new declarative settings schema.
+ *
+ * @param DeclarativeSettingsFormSchemaWithoutValues $schema
+ * @since 29.0.0
+ */
+ public function registerSchema(string $app, array $schema): void;
+
+ /**
+ * Load all schemas from the registration context and events.
+ *
+ * @since 29.0.0
+ */
+ public function loadSchemas(): void;
+
+ /**
+ * Gets the IDs of the forms for the given type and section.
+ *
+ * @param DeclarativeSettingsSectionType $type
+ * @param string $section
+ * @return array<string, list<string>>
+ *
+ * @since 29.0.0
+ */
+ public function getFormIDs(IUser $user, string $type, string $section): array;
+
+ /**
+ * Gets the forms including the field values for the given type and section.
+ *
+ * @param IUser $user Used for reading values from the personal section or for authorization for the admin section.
+ * @param ?DeclarativeSettingsSectionType $type If it is null the forms will not be filtered by type.
+ * @param ?string $section If it is null the forms will not be filtered by section.
+ * @return list<DeclarativeSettingsFormSchemaWithValues>
+ *
+ * @since 29.0.0
+ */
+ public function getFormsWithValues(IUser $user, ?string $type, ?string $section): array;
+
+ /**
+ * Sets a value for the given field ID.
+ *
+ * @param IUser $user Used for storing values in the personal section or for authorization for the admin section.
+ * @param DeclarativeSettingsValueTypes $value
+ *
+ * @throws Exception
+ * @throws NotAdminException
+ *
+ * @since 29.0.0
+ */
+ public function setValue(IUser $user, string $app, string $formId, string $fieldId, mixed $value): void;
+}
diff --git a/lib/public/Settings/IDeclarativeSettingsForm.php b/lib/public/Settings/IDeclarativeSettingsForm.php
new file mode 100644
index 00000000000..7513af8217c
--- /dev/null
+++ b/lib/public/Settings/IDeclarativeSettingsForm.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Settings;
+
+/**
+ * @since 29.0.0
+ *
+ * @psalm-type DeclarativeSettingsSectionType = 'admin'|'personal'
+ *
+ * @psalm-type DeclarativeSettingsStorageType = 'internal'|'external'
+ *
+ * @psalm-type DeclarativeSettingsValueTypes = string|int|float|bool|list<string>
+ *
+ * @psalm-type DeclarativeSettingsFormField = array{
+ * id: string,
+ * title: string,
+ * description?: string,
+ * type: 'text'|'password'|'email'|'tel'|'url'|'number'|'checkbox'|'multi-checkbox'|'radio'|'select'|'multi-select',
+ * placeholder?: string,
+ * label?: string,
+ * default: mixed,
+ * options?: list<string|array{name: string, value: mixed}>,
+ * }
+ *
+ * @psalm-type DeclarativeSettingsFormFieldWithValue = DeclarativeSettingsFormField&array{
+ * value: DeclarativeSettingsValueTypes,
+ * }
+ *
+ * @psalm-type DeclarativeSettingsFormSchema = array{
+ * id: string,
+ * priority: int,
+ * section_type: DeclarativeSettingsSectionType,
+ * section_id: string,
+ * storage_type: DeclarativeSettingsStorageType,
+ * title: string,
+ * description?: string,
+ * doc_url?: string,
+ * }
+ *
+ * @psalm-type DeclarativeSettingsFormSchemaWithValues = DeclarativeSettingsFormSchema&array{
+ * app: string,
+ * fields: list<DeclarativeSettingsFormFieldWithValue>,
+ * }
+ *
+ * @psalm-type DeclarativeSettingsFormSchemaWithoutValues = DeclarativeSettingsFormSchema&array{
+ * fields: list<DeclarativeSettingsFormField>,
+ * }
+ */
+interface IDeclarativeSettingsForm {
+ /**
+ * Gets the schema that defines the declarative settings form
+ *
+ * @return DeclarativeSettingsFormSchemaWithoutValues
+ * @since 29.0.0
+ */
+ public function getSchema(): array;
+}
diff --git a/lib/public/Settings/IManager.php b/lib/public/Settings/IManager.php
index 10de596dbea..dbbbf3f57e4 100644
--- a/lib/public/Settings/IManager.php
+++ b/lib/public/Settings/IManager.php
@@ -6,6 +6,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -34,34 +35,48 @@ use OCP\IUser;
interface IManager {
/**
* @since 9.1.0
+ * @deprecated 29.0.0 Use {@see self::SETTINGS_ADMIN} instead
*/
public const KEY_ADMIN_SETTINGS = 'admin';
/**
* @since 9.1.0
+ * @deprecated 29.0.0 Use {@see self::SETTINGS_ADMIN} instead
*/
public const KEY_ADMIN_SECTION = 'admin-section';
/**
* @since 13.0.0
+ * @deprecated 29.0.0 Use {@see self::SETTINGS_PERSONAL} instead
*/
public const KEY_PERSONAL_SETTINGS = 'personal';
/**
* @since 13.0.0
+ * @deprecated 29.0.0 Use {@see self::SETTINGS_PERSONAL} instead
*/
public const KEY_PERSONAL_SECTION = 'personal-section';
/**
- * @param string $type 'admin-section' or 'personal-section'
- * @param string $section Class must implement OCP\Settings\ISection
+ * @since 29.0.0
+ */
+ public const SETTINGS_ADMIN = 'admin';
+
+ /**
+ * @since 29.0.0
+ */
+ public const SETTINGS_PERSONAL = 'personal';
+
+ /**
+ * @psalm-param self::SETTINGS_* $type
+ * @param class-string<IIconSection> $section
* @since 14.0.0
*/
public function registerSection(string $type, string $section);
/**
- * @param string $type 'admin' or 'personal'
- * @param string $setting Class must implement OCP\Settings\ISettings
+ * @psalm-param self::SETTINGS_* $type
+ * @param class-string<ISettings> $setting
* @since 14.0.0
*/
public function registerSetting(string $type, string $setting);
@@ -69,7 +84,7 @@ interface IManager {
/**
* returns a list of the admin sections
*
- * @return array<int, array<int, IIconSection>> array from IConSection[] where key is the priority
+ * @return array<int, list<IIconSection>> list of sections with priority as key
* @since 9.1.0
*/
public function getAdminSections(): array;
@@ -77,7 +92,7 @@ interface IManager {
/**
* returns a list of the personal sections
*
- * @return array array of ISection[] where key is the priority
+ * @return array<int, list<IIconSection>> list of sections with priority as key
* @since 13.0.0
*/
public function getPersonalSections(): array;
@@ -87,10 +102,10 @@ interface IManager {
*
* @param string $section the section id for which to load the settings
* @param bool $subAdminOnly only return settings sub admins are supposed to see (since 17.0.0)
- * @return array<int, array<int, ISettings>> array of ISettings[] where key is the priority
+ * @return array<int, list<ISettings>> list of settings with priority as key
* @since 9.1.0
*/
- public function getAdminSettings($section, bool $subAdminOnly = false): array;
+ public function getAdminSettings(string $section, bool $subAdminOnly = false): array;
/**
* Returns a list of admin settings that the given user can use for the give section
@@ -103,7 +118,7 @@ interface IManager {
/**
* Returns a list of admin settings that the given user can use.
*
- * @return array<int, list<ISettings>> The array of admin settings there admin delegation is allowed.
+ * @return list<ISettings> The array of admin settings there admin delegation is allowed.
* @since 23.0.0
*/
public function getAllAllowedAdminSettings(IUser $user): array;
@@ -112,13 +127,14 @@ interface IManager {
* returns a list of the personal settings
*
* @param string $section the section id for which to load the settings
- * @return array array of ISettings[] where key is the priority
+ * @return array<int, list<ISettings>> list of settings with priority as key
* @since 13.0.0
*/
- public function getPersonalSettings($section): array;
+ public function getPersonalSettings(string $section): array;
/**
* Get a specific section by type and id
+ * @psalm-param self::SETTINGS_* $type
* @since 25.0.0
*/
public function getSection(string $type, string $sectionId): ?IIconSection;
diff --git a/lib/public/SetupCheck/ISetupCheck.php b/lib/public/SetupCheck/ISetupCheck.php
new file mode 100644
index 00000000000..96eb6ddd7da
--- /dev/null
+++ b/lib/public/SetupCheck/ISetupCheck.php
@@ -0,0 +1,53 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SetupCheck;
+
+/**
+ * This interface needs to be implemented if you want to provide custom
+ * setup checks in your application. The results of these checks will them
+ * be displayed in the admin overview.
+ *
+ * @since 28.0.0
+ */
+interface ISetupCheck {
+ /**
+ * @since 28.0.0
+ * @return string Category id, one of security/system/accounts, or a custom one which will be merged in system
+ */
+ public function getCategory(): string;
+
+ /**
+ * @since 28.0.0
+ * @return string Translated name to display to the user
+ */
+ public function getName(): string;
+
+ /**
+ * @since 28.0.0
+ */
+ public function run(): SetupResult;
+}
diff --git a/lib/public/SetupCheck/ISetupCheckManager.php b/lib/public/SetupCheck/ISetupCheckManager.php
new file mode 100644
index 00000000000..4b963e7c6b8
--- /dev/null
+++ b/lib/public/SetupCheck/ISetupCheckManager.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @author Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SetupCheck;
+
+/**
+ * @since 28.0.0
+ */
+interface ISetupCheckManager {
+ /**
+ * @since 28.0.0
+ * @return array<string,array<string,SetupResult>> Result of each check, first level key is category, second level key is title
+ */
+ public function runAll(): array;
+}
diff --git a/lib/public/SetupCheck/SetupResult.php b/lib/public/SetupCheck/SetupResult.php
new file mode 100644
index 00000000000..7ae4cfcba24
--- /dev/null
+++ b/lib/public/SetupCheck/SetupResult.php
@@ -0,0 +1,204 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Côme Chilliet <come.chilliet@nextcloud.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\SetupCheck;
+
+use OCP\RichObjectStrings\IValidator;
+
+/**
+ * @brief This class is used for storing the result of a setup check
+ *
+ * @since 28.0.0
+ */
+class SetupResult implements \JsonSerializable {
+ /**
+ * @since 28.0.0
+ */
+ public const SUCCESS = 'success';
+
+ /**
+ * @since 28.0.0
+ */
+ public const INFO = 'info';
+
+ /**
+ * @since 28.0.0
+ */
+ public const WARNING = 'warning';
+
+ /**
+ * @since 28.0.0
+ */
+ public const ERROR = 'error';
+
+ /**
+ * @param string $name Translated name to display to the user
+ */
+ private ?string $name = null;
+
+ /**
+ * @brief Private constructor, use success()/info()/warning()/error() instead
+ * @param self::SUCCESS|self::INFO|self::WARNING|self::ERROR $severity
+ * @throws \OCP\RichObjectStrings\InvalidObjectExeption
+ * @since 28.0.0
+ * @since 28.0.2 Optional parameter ?array $descriptionParameters
+ * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption
+ */
+ private function __construct(
+ private string $severity,
+ private ?string $description = null,
+ private ?array $descriptionParameters = null,
+ private ?string $linkToDoc = null,
+ ) {
+ if ($description !== null && $descriptionParameters !== null) {
+ \OCP\Server::get(IValidator::class)->validate($description, $descriptionParameters);
+ }
+ }
+
+ /**
+ * @brief Create a success result object
+ * @param ?string $description Translated detailed description to display to the user
+ * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project
+ * @throws \OCP\RichObjectStrings\InvalidObjectExeption
+ * @since 28.0.0
+ * @since 28.0.2 Optional parameter ?array $descriptionParameters
+ * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption
+ */
+ public static function success(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self {
+ return new self(self::SUCCESS, $description, $descriptionParameters, $linkToDoc);
+ }
+
+ /**
+ * @brief Create an info result object
+ * @param ?string $description Translated detailed description to display to the user
+ * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project
+ * @throws \OCP\RichObjectStrings\InvalidObjectExeption
+ * @since 28.0.0
+ * @since 28.0.2 Optional parameter ?array $descriptionParameters
+ * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption
+ */
+ public static function info(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self {
+ return new self(self::INFO, $description, $descriptionParameters, $linkToDoc);
+ }
+
+ /**
+ * @brief Create a warning result object
+ * @param ?string $description Translated detailed description to display to the user
+ * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project
+ * @throws \OCP\RichObjectStrings\InvalidObjectExeption
+ * @since 28.0.0
+ * @since 28.0.2 Optional parameter ?array $descriptionParameters
+ * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption
+ */
+ public static function warning(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self {
+ return new self(self::WARNING, $description, $descriptionParameters, $linkToDoc);
+ }
+
+ /**
+ * @brief Create an error result object
+ * @param ?string $description Translated detailed description to display to the user
+ * @param ?string $linkToDoc URI of related relevent documentation, be it from Nextcloud or another project
+ * @throws \OCP\RichObjectStrings\InvalidObjectExeption
+ * @since 28.0.0
+ * @since 28.0.2 Optional parameter ?array $descriptionParameters
+ * @since 28.0.2 throws \OCP\RichObjectStrings\InvalidObjectExeption
+ */
+ public static function error(?string $description = null, ?string $linkToDoc = null, ?array $descriptionParameters = null): self {
+ return new self(self::ERROR, $description, $descriptionParameters, $linkToDoc);
+ }
+
+ /**
+ * @brief Get the severity for the setup check result
+ *
+ * @return self::SUCCESS|self::INFO|self::WARNING|self::ERROR
+ * @since 28.0.0
+ */
+ public function getSeverity(): string {
+ return $this->severity;
+ }
+
+ /**
+ * @brief Get the description for the setup check result
+ *
+ * @since 28.0.0
+ */
+ public function getDescription(): ?string {
+ return $this->description;
+ }
+
+ /**
+ * @brief Get the description parameters for the setup check result
+ *
+ * If this returns null, description must not be treated as rich text
+ *
+ * @since 28.0.2
+ */
+ public function getDescriptionParameters(): ?array {
+ return $this->descriptionParameters;
+ }
+
+ /**
+ * @brief Get the name for the setup check
+ *
+ * @since 28.0.0
+ */
+ public function getName(): ?string {
+ return $this->name;
+ }
+
+ /**
+ * @brief Set the name from the setup check
+ *
+ * @since 28.0.0
+ */
+ public function setName(string $name): void {
+ $this->name = $name;
+ }
+
+ /**
+ * @brief Get a link to the doc for the explanation.
+ *
+ * @since 28.0.0
+ */
+ public function getLinkToDoc(): ?string {
+ return $this->linkToDoc;
+ }
+
+ /**
+ * @brief Get an array representation of the result for API responses
+ *
+ * @since 28.0.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'name' => $this->name,
+ 'severity' => $this->severity,
+ 'description' => $this->description,
+ 'descriptionParameters' => $this->descriptionParameters,
+ 'linkToDoc' => $this->linkToDoc,
+ ];
+ }
+}
diff --git a/lib/public/Share.php b/lib/public/Share.php
index 9499cdb14b6..2004f77cf0a 100644
--- a/lib/public/Share.php
+++ b/lib/public/Share.php
@@ -33,8 +33,7 @@
namespace OCP;
/**
- * This class provides the ability for apps to share their content between users.
- * Apps must create a backend class that implements OCP\Share_Backend and register it with this class.
+ * This class remains only for use with the ::class namespace used for various hooks
*
* It provides the following hooks:
* - post_shared
@@ -42,95 +41,4 @@ namespace OCP;
* @deprecated 17.0.0
*/
class Share extends \OC\Share\Constants {
- /**
- * Get the item of item type shared with a given user by source
- * @param string $itemType
- * @param string $itemSource
- * @param string $user User to whom the item was shared
- * @param string $owner Owner of the share
- * @return array Return list of items with file_target, permissions and expiration
- * @since 6.0.0 - parameter $owner was added in 8.0.0
- * @deprecated 17.0.0
- */
- public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null) {
- return \OC\Share\Share::getItemSharedWithUser($itemType, $itemSource, $user, $owner);
- }
-
- /**
- * Get the item of item type shared with the current user by source
- * @param string $itemType
- * @param string $itemSource
- * @param int $format (optional) Format type must be defined by the backend
- * @param mixed $parameters
- * @param bool $includeCollections
- * @return void
- * @since 5.0.0
- * @deprecated 17.0.0
- */
- public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
- $parameters = null, $includeCollections = false) {
- // not used by any app - only here to not break apps syntax
- }
-
- /**
- * Based on the given token the share information will be returned - password protected shares will be verified
- * @param string $token
- * @param bool $checkPasswordProtection
- * @return void
- * @since 5.0.0 - parameter $checkPasswordProtection was added in 7.0.0
- * @deprecated 17.0.0
- */
- public static function getShareByToken($token, $checkPasswordProtection = true) {
- // not used by any app - only here to not break apps syntax
- }
-
-
- /**
- * Get the shared items of item type owned by the current user
- * @param string $itemType
- * @param int $format (optional) Format type must be defined by the backend
- * @param mixed $parameters
- * @param int $limit Number of items to return (optional) Returns all by default
- * @param bool $includeCollections
- * @return void
- * @since 5.0.0
- * @deprecated 17.0.0
- */
- public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
- $limit = -1, $includeCollections = false) {
- // only used by AppVNCSafe app (https://github.com/vnc-biz/nextcloud-appvncsafe/issues/2) - only here to not break apps syntax
- }
-
- /**
- * Get the shared item of item type owned by the current user
- * @param string $itemType
- * @param string $itemSource
- * @param int $format (optional) Format type must be defined by the backend
- * @param mixed $parameters
- * @param bool $includeCollections
- * @return mixed Return depends on format
- * @since 5.0.0
- * @deprecated 17.0.0
- *
- * Refactoring notes:
- * * defacto $parameters and $format is always the default and therefore is removed in the subsequent call
- */
- public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
- $parameters = null, $includeCollections = false) {
- return \OC\Share\Share::getItemShared($itemType, $itemSource, self::FORMAT_NONE, null, $includeCollections);
- }
-
- /**
- * sent status if users got informed by mail about share
- * @param string $itemType
- * @param string $itemSource
- * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string $recipient with whom was the item shared
- * @param bool $status
- * @since 6.0.0 - parameter $originIsSource was added in 8.0.0
- * @deprecated 17.0.0
- */
- public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
- // not used by any app - only here to not break apps syntax
- }
}
diff --git a/lib/public/Share/Events/VerifyMountPointEvent.php b/lib/public/Share/Events/VerifyMountPointEvent.php
index 650f4ad2245..af71314930b 100644
--- a/lib/public/Share/Events/VerifyMountPointEvent.php
+++ b/lib/public/Share/Events/VerifyMountPointEvent.php
@@ -44,8 +44,8 @@ class VerifyMountPointEvent extends Event {
* @since 19.0.0
*/
public function __construct(IShare $share,
- View $view,
- string $parent) {
+ View $view,
+ string $parent) {
parent::__construct();
$this->share = $share;
diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php
index 9ac224ed7ef..07517dd7eb5 100644
--- a/lib/public/Share/IManager.php
+++ b/lib/public/Share/IManager.php
@@ -416,6 +416,15 @@ interface IManager {
public function shareWithGroupMembersOnly();
/**
+ * If shareWithGroupMembersOnly is enabled, return an optional
+ * list of groups that must be excluded from the principle of
+ * belonging to the same group.
+ * @return array
+ * @since 27.0.0
+ */
+ public function shareWithGroupMembersOnlyExcludeGroupsList();
+
+ /**
* Check if users can share with groups
* @return bool
* @since 9.0.1
diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php
index 40548c6c73d..a059696a75e 100644
--- a/lib/public/Share/IShare.php
+++ b/lib/public/Share/IShare.php
@@ -213,7 +213,7 @@ interface IShare {
* @since 9.0.0
* @throws NotFoundException
*/
- public function getNodeId();
+ public function getNodeId(): int;
/**
* Set the type of node (file/folder)
@@ -394,7 +394,7 @@ interface IShare {
/**
* Get the expiration date
*
- * @return \DateTime
+ * @return null|\DateTime
* @since 9.0.0
*/
public function getExpirationDate();
@@ -474,7 +474,7 @@ interface IShare {
* If this share is obtained via a shareprovider the password is
* hashed.
*
- * @return string
+ * @return string|null
* @since 9.0.0
*/
public function getPassword();
diff --git a/lib/public/Share/IShareProvider.php b/lib/public/Share/IShareProvider.php
index b6e0c4ba38b..2a37508d449 100644
--- a/lib/public/Share/IShareProvider.php
+++ b/lib/public/Share/IShareProvider.php
@@ -70,7 +70,7 @@ interface IShareProvider {
* @return IShare The share object
* @since 17.0.0
*/
-// public function acceptShare(IShare $share, string $recipient): IShare;
+ // public function acceptShare(IShare $share, string $recipient): IShare;
/**
* Delete a share
diff --git a/lib/public/SpeechToText/ISpeechToTextProviderWithId.php b/lib/public/SpeechToText/ISpeechToTextProviderWithId.php
new file mode 100644
index 00000000000..0fb337f4602
--- /dev/null
+++ b/lib/public/SpeechToText/ISpeechToTextProviderWithId.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace OCP\SpeechToText;
+
+/**
+ * @since 28.0.0
+ */
+interface ISpeechToTextProviderWithId extends ISpeechToTextProvider {
+
+ /**
+ * @since 28.0.0
+ */
+ public function getId(): string;
+}
diff --git a/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php b/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php
new file mode 100644
index 00000000000..2a9b667171d
--- /dev/null
+++ b/lib/public/SpeechToText/ISpeechToTextProviderWithUserId.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2024 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace OCP\SpeechToText;
+
+/**
+ * @since 29.0.0
+ */
+interface ISpeechToTextProviderWithUserId extends ISpeechToTextProvider {
+ /**
+ * @since 29.0.0
+ */
+ public function setUserId(?string $userId): void;
+}
diff --git a/lib/public/SystemTag/ManagerEvent.php b/lib/public/SystemTag/ManagerEvent.php
index 704aecd4536..48bd651f7a3 100644
--- a/lib/public/SystemTag/ManagerEvent.php
+++ b/lib/public/SystemTag/ManagerEvent.php
@@ -37,16 +37,19 @@ use OCP\EventDispatcher\Event;
*/
class ManagerEvent extends Event {
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_CREATE = 'OCP\SystemTag\ISystemTagManager::createTag';
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_UPDATE = 'OCP\SystemTag\ISystemTagManager::updateTag';
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_DELETE = 'OCP\SystemTag\ISystemTagManager::deleteTag';
diff --git a/lib/public/SystemTag/MapperEvent.php b/lib/public/SystemTag/MapperEvent.php
index 6aa0ea77000..cbd1b2ff2db 100644
--- a/lib/public/SystemTag/MapperEvent.php
+++ b/lib/public/SystemTag/MapperEvent.php
@@ -36,11 +36,13 @@ use OCP\EventDispatcher\Event;
*/
class MapperEvent extends Event {
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_ASSIGN = 'OCP\SystemTag\ISystemTagObjectMapper::assignTags';
/**
+ * @since 9.0.0
* @deprecated 22.0.0
*/
public const EVENT_UNASSIGN = 'OCP\SystemTag\ISystemTagObjectMapper::unassignTags';
diff --git a/lib/public/SystemTag/SystemTagsEntityEvent.php b/lib/public/SystemTag/SystemTagsEntityEvent.php
index 0ce679a3a43..252029e6ba2 100644
--- a/lib/public/SystemTag/SystemTagsEntityEvent.php
+++ b/lib/public/SystemTag/SystemTagsEntityEvent.php
@@ -37,6 +37,7 @@ use OCP\EventDispatcher\Event;
*/
class SystemTagsEntityEvent extends Event {
/**
+ * @since 9.1.0
* @deprecated 22.0.0 Listen to the typed event instead
*/
public const EVENT_ENTITY = 'OCP\SystemTag\ISystemTagManager::registerEntity';
diff --git a/lib/public/Talk/IBroker.php b/lib/public/Talk/IBroker.php
index d3b6e1429e6..f2b512ea4a8 100644
--- a/lib/public/Talk/IBroker.php
+++ b/lib/public/Talk/IBroker.php
@@ -68,8 +68,8 @@ interface IBroker {
* @since 24.0.0
*/
public function createConversation(string $name,
- array $moderators,
- IConversationOptions $options = null): IConversation;
+ array $moderators,
+ IConversationOptions $options = null): IConversation;
/**
* Delete a conversation by id
diff --git a/lib/public/Talk/ITalkBackend.php b/lib/public/Talk/ITalkBackend.php
index 3ee995576a4..a2f4d962019 100644
--- a/lib/public/Talk/ITalkBackend.php
+++ b/lib/public/Talk/ITalkBackend.php
@@ -46,8 +46,8 @@ interface ITalkBackend {
* @since 24.0.0
*/
public function createConversation(string $name,
- array $moderators,
- IConversationOptions $options): IConversation;
+ array $moderators,
+ IConversationOptions $options): IConversation;
/**
* Delete a conversation by id
diff --git a/lib/public/Teams/ITeamManager.php b/lib/public/Teams/ITeamManager.php
new file mode 100644
index 00000000000..51d8a1feb5a
--- /dev/null
+++ b/lib/public/Teams/ITeamManager.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Teams;
+
+/**
+ * @since 29.0.0
+ */
+interface ITeamManager {
+ /**
+ * Get all providers that have registered as a team resource provider
+ *
+ * @return ITeamResourceProvider[]
+ * @since 29.0.0
+ */
+ public function getProviders(): array;
+
+ /**
+ * Get a specific team resource provider by its id
+ *
+ * @since 29.0.0
+ */
+ public function getProvider(string $providerId): ITeamResourceProvider;
+
+ /**
+ * Returns all team resources for a given team and user
+ *
+ * @return TeamResource[]
+ * @since 29.0.0
+ */
+ public function getSharedWith(string $teamId, string $userId): array;
+
+ /**
+ * Returns all teams for a given resource and user
+ *
+ * @since 29.0.0
+ */
+ public function getTeamsForResource(string $providerId, string $resourceId, string $userId): array;
+}
diff --git a/lib/public/Teams/ITeamResourceProvider.php b/lib/public/Teams/ITeamResourceProvider.php
new file mode 100644
index 00000000000..722c877555e
--- /dev/null
+++ b/lib/public/Teams/ITeamResourceProvider.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Teams;
+
+/**
+ * Implement a provider of resources that are shared or owned by a team
+ *
+ * @since 29.0.0
+ */
+interface ITeamResourceProvider {
+
+ /**
+ * Unique identifier used to identify the provider (app id)
+ *
+ * @since 29.0.0
+ */
+ public function getId(): string;
+
+ /**
+ * User visible name of the provider (app name)
+ *
+ * @since 29.0.0
+ */
+ public function getName(): string;
+
+ /**
+ * Svg icon to show next to the provider (app icon)
+ *
+ * @since 29.0.0
+ */
+ public function getIconSvg(): string;
+
+ /**
+ * Return all resources that are shared to the given team id for the current provider
+ *
+ * @param string $teamId
+ * @return TeamResource[]
+ * @since 29.0.0
+ */
+ public function getSharedWith(string $teamId): array;
+
+ /**
+ * Check if a resource is shared with the given team
+ *
+ * @since 29.0.0
+ */
+ public function isSharedWithTeam(string $teamId, string $resourceId): bool;
+
+ /**
+ * Return team ids that a resource is shared with or owned by
+ *
+ * @return string[]
+ * @since 29.0.0
+ */
+ public function getTeamsForResource(string $resourceId): array;
+}
diff --git a/lib/public/Teams/Team.php b/lib/public/Teams/Team.php
new file mode 100644
index 00000000000..d3d6c2d143d
--- /dev/null
+++ b/lib/public/Teams/Team.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Teams;
+
+/**
+ * Simple abstraction to represent a team in the public API
+ *
+ * In the backend a team is a circle identified by the circles singleId
+ *
+ * @since 29.0.0
+ */
+class Team implements \JsonSerializable {
+
+ /**
+ * @since 29.0.0
+ */
+ public function __construct(private string $teamId, private string $displayName, private ?string $link) {
+ }
+
+ /**
+ * Unique identifier of the team (singleId of the circle)
+ *
+ * @since 29.0.0
+ */
+ public function getId(): string {
+ return $this->teamId;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getDisplayName(): string {
+ return $this->displayName;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function getLink(): ?string {
+ return $this->link;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'teamId' => $this->teamId,
+ 'displayName' => $this->displayName,
+ 'link' => $this->link,
+ ];
+ }
+}
diff --git a/lib/public/Teams/TeamResource.php b/lib/public/Teams/TeamResource.php
new file mode 100644
index 00000000000..569583bb393
--- /dev/null
+++ b/lib/public/Teams/TeamResource.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Teams;
+
+/**
+ * @since 29.0.0
+ */
+class TeamResource implements \JsonSerializable {
+ /**
+ * @since 29.0.0
+ */
+ public function __construct(
+ private ITeamResourceProvider $teamResourceProvider,
+ private string $resourceId,
+ private string $label,
+ private string $url,
+ private ?string $iconSvg = null,
+ private ?string $iconURL = null,
+ private ?string $iconEmoji = null,
+ ) {
+ }
+
+ /**
+ * Returns the provider details for the current resource
+ *
+ * @since 29.0.0
+ */
+ public function getProvider(): ITeamResourceProvider {
+ return $this->teamResourceProvider;
+ }
+
+ /**
+ * Unique id of the resource (e.g. primary key id)
+ * @since 29.0.0
+ */
+ public function getId(): string {
+ return $this->resourceId;
+ }
+
+ /**
+ * User visible label when listing resources
+ *
+ * @since 29.0.0
+ */
+ public function getLabel(): string {
+ return $this->label;
+ }
+
+ /**
+ * Absolute url to navigate the user to the resource
+ *
+ * @since 29.0.0
+ */
+ public function getUrl(): string {
+ return $this->url;
+ }
+
+ /**
+ * Svg icon to show next to the name for the resource
+ *
+ * From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl
+ *
+ * @since 29.0.0
+ */
+ public function getIconSvg(): ?string {
+ return $this->iconSvg;
+ }
+
+ /**
+ * Image url of the icon to show next to the name for the resource
+ *
+ * From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl
+ *
+ * @since 29.0.0
+ */
+ public function getIconURL(): ?string {
+ return $this->iconURL;
+ }
+
+ /**
+ * Emoji show next to the name for the resource
+ *
+ * From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl
+ *
+ * @since 29.0.0
+ */
+ public function getIconEmoji(): ?string {
+ return $this->iconEmoji;
+ }
+
+ /**
+ * @since 29.0.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'id' => $this->resourceId,
+ 'label' => $this->label,
+ 'url' => $this->url,
+ 'iconSvg' => $this->iconSvg,
+ 'iconURL' => $this->iconURL,
+ 'iconEmoji' => $this->iconEmoji,
+ 'provider' => [
+ 'id' => $this->teamResourceProvider->getId(),
+ 'name' => $this->teamResourceProvider->getName(),
+ 'icon' => $this->teamResourceProvider->getIconSvg(),
+ ]
+ ];
+ }
+}
diff --git a/lib/public/TextProcessing/Exception/TaskFailureException.php b/lib/public/TextProcessing/Exception/TaskFailureException.php
new file mode 100644
index 00000000000..300864711e7
--- /dev/null
+++ b/lib/public/TextProcessing/Exception/TaskFailureException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace OCP\TextProcessing\Exception;
+
+/**
+ * Exception thrown when a task failed
+ * @since 28.0.0
+ */
+class TaskFailureException extends \RuntimeException {
+}
diff --git a/lib/public/TextProcessing/IManager.php b/lib/public/TextProcessing/IManager.php
index dec0baba4bb..2f517a4ebe2 100644
--- a/lib/public/TextProcessing/IManager.php
+++ b/lib/public/TextProcessing/IManager.php
@@ -27,7 +27,9 @@ declare(strict_types=1);
namespace OCP\TextProcessing;
use OCP\Common\Exception\NotFoundException;
+use OCP\DB\Exception;
use OCP\PreConditionNotMetException;
+use OCP\TextProcessing\Exception\TaskFailureException;
use RuntimeException;
/**
@@ -48,7 +50,7 @@ interface IManager {
public function getProviders(): array;
/**
- * @return class-string<ITaskType>[]
+ * @return string[]
* @since 27.1.0
*/
public function getAvailableTaskTypes(): array;
@@ -56,7 +58,7 @@ interface IManager {
/**
* @param Task $task The task to run
* @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called
- * @throws RuntimeException If something else failed
+ * @throws TaskFailureException If running the task failed
* @since 27.1.0
*/
public function runTask(Task $task): string;
@@ -68,11 +70,26 @@ interface IManager {
*
* @param Task $task The task to schedule
* @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called
+ * @throws Exception storing the task in the database failed
* @since 27.1.0
*/
public function scheduleTask(Task $task) : void;
/**
+ * If the designated provider for the passed task provides an expected average runtime, we check if the runtime fits into the
+ * max execution time of this php process and run it synchronously if it does, if it doesn't fit (or the provider doesn't provide that information)
+ * execution is deferred to a background job
+ *
+ * @param Task $task The task to schedule
+ * @returns bool A boolean indicating whether the task was run synchronously (`true`) or offloaded to a background job (`false`)
+ * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called
+ * @throws TaskFailureException If running the task failed
+ * @throws Exception storing the task in the database failed
+ * @since 28.0.0
+ */
+ public function runOrScheduleTask(Task $task): bool;
+
+ /**
* Delete a task that has been scheduled before
*
* @param Task $task The task to delete
diff --git a/lib/public/TextProcessing/IProvider.php b/lib/public/TextProcessing/IProvider.php
index 6132e60b493..fc57add1835 100644
--- a/lib/public/TextProcessing/IProvider.php
+++ b/lib/public/TextProcessing/IProvider.php
@@ -31,7 +31,7 @@ use RuntimeException;
/**
* This is the interface that is implemented by apps that
* implement a text processing provider
- * @template T of ITaskType
+ * @psalm-template-covariant T of ITaskType
* @since 27.1.0
*/
interface IProvider {
diff --git a/lib/public/TextProcessing/IProviderWithExpectedRuntime.php b/lib/public/TextProcessing/IProviderWithExpectedRuntime.php
new file mode 100644
index 00000000000..17767fc02d4
--- /dev/null
+++ b/lib/public/TextProcessing/IProviderWithExpectedRuntime.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace OCP\TextProcessing;
+
+/**
+ * This interface allows the system to learn the provider's expected runtime
+ * @since 28.0.0
+ * @template T of ITaskType
+ * @template-extends IProvider<T>
+ */
+interface IProviderWithExpectedRuntime extends IProvider {
+ /**
+ * @return int The expected average runtime of a task in seconds
+ * @since 28.0.0
+ */
+ public function getExpectedRuntime(): int;
+}
diff --git a/lib/public/TextProcessing/IProviderWithId.php b/lib/public/TextProcessing/IProviderWithId.php
new file mode 100644
index 00000000000..1bd02278d1c
--- /dev/null
+++ b/lib/public/TextProcessing/IProviderWithId.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\TextProcessing;
+
+/**
+ * @since 28.0.0
+ * @extends IProvider<T>
+ * @template T of ITaskType
+ */
+interface IProviderWithId extends IProvider {
+ /**
+ * The id of this provider
+ * @since 28.0.0
+ */
+ public function getId(): string;
+}
diff --git a/lib/public/TextProcessing/IProviderWithUserId.php b/lib/public/TextProcessing/IProviderWithUserId.php
new file mode 100644
index 00000000000..0a01a4c56c4
--- /dev/null
+++ b/lib/public/TextProcessing/IProviderWithUserId.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace OCP\TextProcessing;
+
+/**
+ * This interface allows providers to access the user that initiated the task being run.
+ * @since 28.0.0
+ * @template T of ITaskType
+ * @template-extends IProvider<T>
+ */
+interface IProviderWithUserId extends IProvider {
+ /**
+ * @param ?string $userId the current user's id
+ * @since 28.0.0
+ */
+ public function setUserId(?string $userId): void;
+}
diff --git a/lib/public/TextProcessing/Task.php b/lib/public/TextProcessing/Task.php
index 446e414cb04..c62b7b2fff8 100644
--- a/lib/public/TextProcessing/Task.php
+++ b/lib/public/TextProcessing/Task.php
@@ -28,13 +28,12 @@ namespace OCP\TextProcessing;
/**
* This is a text processing task
* @since 27.1.0
- * @psalm-template T of ITaskType
- * @psalm-template S as class-string<T>
- * @psalm-template P as IProvider<T>
+ * @psalm-template-covariant T of ITaskType
*/
final class Task implements \JsonSerializable {
protected ?int $id = null;
protected ?string $output = null;
+ private ?\DateTime $completionExpectedAt = null;
/**
* @since 27.1.0
@@ -73,7 +72,7 @@ final class Task implements \JsonSerializable {
protected int $status = self::STATUS_UNKNOWN;
/**
- * @psalm-param S $type
+ * @psalm-param class-string<T> $type
* @param string $type
* @param string $input
* @param string $appId
@@ -91,13 +90,16 @@ final class Task implements \JsonSerializable {
}
/**
- * @psalm-param P $provider
+ * @psalm-param IProvider<T> $provider
* @param IProvider $provider
* @return string
* @since 27.1.0
*/
public function visitProvider(IProvider $provider): string {
if ($this->canUseProvider($provider)) {
+ if ($provider instanceof IProviderWithUserId) {
+ $provider->setUserId($this->getUserId());
+ }
return $provider->process($this->getInput());
} else {
throw new \RuntimeException('Task of type ' . $this->getType() . ' cannot visit provider with task type ' . $provider->getTaskType());
@@ -105,7 +107,7 @@ final class Task implements \JsonSerializable {
}
/**
- * @psalm-param P $provider
+ * @psalm-param IProvider<T> $provider
* @param IProvider $provider
* @return bool
* @since 27.1.0
@@ -115,7 +117,7 @@ final class Task implements \JsonSerializable {
}
/**
- * @psalm-return S
+ * @psalm-return class-string<T>
* @since 27.1.0
*/
final public function getType(): string {
@@ -203,7 +205,7 @@ final class Task implements \JsonSerializable {
}
/**
- * @psalm-return array{id: ?int, type: S, status: 0|1|2|3|4, userId: ?string, appId: string, input: string, output: ?string, identifier: string}
+ * @psalm-return array{id: ?int, type: class-string<T>, status: 0|1|2|3|4, userId: ?string, appId: string, input: string, output: ?string, identifier: string, completionExpectedAt: ?int}
* @since 27.1.0
*/
public function jsonSerialize(): array {
@@ -216,6 +218,24 @@ final class Task implements \JsonSerializable {
'input' => $this->getInput(),
'output' => $this->getOutput(),
'identifier' => $this->getIdentifier(),
+ 'completionExpectedAt' => $this->getCompletionExpectedAt()?->getTimestamp(),
];
}
+
+ /**
+ * @param null|\DateTime $completionExpectedAt
+ * @return void
+ * @since 28.0.0
+ */
+ final public function setCompletionExpectedAt(?\DateTime $completionExpectedAt): void {
+ $this->completionExpectedAt = $completionExpectedAt;
+ }
+
+ /**
+ * @return \DateTime|null
+ * @since 28.0.0
+ */
+ final public function getCompletionExpectedAt(): ?\DateTime {
+ return $this->completionExpectedAt;
+ }
}
diff --git a/lib/public/TextToImage/Events/AbstractTextToImageEvent.php b/lib/public/TextToImage/Events/AbstractTextToImageEvent.php
new file mode 100644
index 00000000000..56c68195602
--- /dev/null
+++ b/lib/public/TextToImage/Events/AbstractTextToImageEvent.php
@@ -0,0 +1,52 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\TextToImage\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\TextToImage\Task;
+
+/**
+ * @since 28.0.0
+ */
+abstract class AbstractTextToImageEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(
+ private Task $task
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @return Task
+ * @since 28.0.0
+ */
+ public function getTask(): Task {
+ return $this->task;
+ }
+}
diff --git a/lib/public/TextToImage/Events/TaskFailedEvent.php b/lib/public/TextToImage/Events/TaskFailedEvent.php
new file mode 100644
index 00000000000..0d91b3a4f67
--- /dev/null
+++ b/lib/public/TextToImage/Events/TaskFailedEvent.php
@@ -0,0 +1,54 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\TextToImage\Events;
+
+use OCP\TextToImage\Task;
+
+/**
+ * @since 28.0.0
+ */
+class TaskFailedEvent extends AbstractTextToImageEvent {
+ /**
+ * @param Task $task
+ * @param string $errorMessage
+ * @since 28.0.0
+ */
+ public function __construct(
+ Task $task,
+ private string $errorMessage,
+ ) {
+ parent::__construct($task);
+ }
+
+ /**
+ * @return string
+ * @since 28.0.0
+ */
+ public function getErrorMessage(): string {
+ return $this->errorMessage;
+ }
+}
diff --git a/lib/public/TextToImage/Events/TaskSuccessfulEvent.php b/lib/public/TextToImage/Events/TaskSuccessfulEvent.php
new file mode 100644
index 00000000000..15d263c0ff0
--- /dev/null
+++ b/lib/public/TextToImage/Events/TaskSuccessfulEvent.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\TextToImage\Events;
+
+/**
+ * @since 28.0.0
+ */
+class TaskSuccessfulEvent extends AbstractTextToImageEvent {
+}
diff --git a/lib/public/TextToImage/Exception/TaskFailureException.php b/lib/public/TextToImage/Exception/TaskFailureException.php
new file mode 100644
index 00000000000..a640fdff2e8
--- /dev/null
+++ b/lib/public/TextToImage/Exception/TaskFailureException.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\TextToImage\Exception;
+
+/**
+ * @since 28.0.0
+ */
+class TaskFailureException extends TextToImageException {
+}
diff --git a/lib/public/TextToImage/Exception/TaskNotFoundException.php b/lib/public/TextToImage/Exception/TaskNotFoundException.php
new file mode 100644
index 00000000000..bd713fe3905
--- /dev/null
+++ b/lib/public/TextToImage/Exception/TaskNotFoundException.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\TextToImage\Exception;
+
+/**
+ * @since 28.0.0
+ */
+class TaskNotFoundException extends TextToImageException {
+}
diff --git a/lib/public/TextToImage/Exception/TextToImageException.php b/lib/public/TextToImage/Exception/TextToImageException.php
new file mode 100644
index 00000000000..3d4fd192c94
--- /dev/null
+++ b/lib/public/TextToImage/Exception/TextToImageException.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\TextToImage\Exception;
+
+/**
+ * @since 28.0.0
+ */
+class TextToImageException extends \Exception {
+}
diff --git a/lib/public/TextToImage/IManager.php b/lib/public/TextToImage/IManager.php
new file mode 100644
index 00000000000..f2092476e78
--- /dev/null
+++ b/lib/public/TextToImage/IManager.php
@@ -0,0 +1,116 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace OCP\TextToImage;
+
+use OCP\DB\Exception;
+use OCP\PreConditionNotMetException;
+use OCP\TextToImage\Exception\TaskFailureException;
+use OCP\TextToImage\Exception\TaskNotFoundException;
+use RuntimeException;
+
+/**
+ * API surface for apps interacting with and making use of TextToImage providers
+ * without knowing which providers are installed
+ * @since 28.0.0
+ */
+interface IManager {
+ /**
+ * @since 28.0.0
+ */
+ public function hasProviders(): bool;
+
+ /**
+ * @since 28.0.0
+ * @return list<IProvider>
+ */
+ public function getProviders(): array;
+
+ /**
+ * @param Task $task The task to run
+ * @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called
+ * @throws TaskFailureException If something else failed. When this is thrown task status was already set to failure.
+ * @since 28.0.0
+ */
+ public function runTask(Task $task): void;
+
+ /**
+ * Will schedule a TextToImage process in the background. The result will become available
+ * with the \OCP\TextToImage\TaskSuccessfulEvent
+ * If inference fails a \OCP\TextToImage\Events\TaskFailedEvent will be dispatched instead
+ *
+ * @param Task $task The task to schedule
+ * @throws PreConditionNotMetException If no provider was registered but this method was still called
+ * @throws Exception If there was a problem inserting the task into the database
+ * @since 28.0.0
+ */
+ public function scheduleTask(Task $task) : void;
+
+ /**
+ * @throws Exception if there was a problem inserting the task into the database
+ * @throws PreConditionNotMetException if no provider is registered
+ * @throws TaskFailureException If the task run failed
+ * @since 28.0.0
+ */
+ public function runOrScheduleTask(Task $task) : void;
+
+ /**
+ * Delete a task that has been scheduled before
+ *
+ * @param Task $task The task to delete
+ * @since 28.0.0
+ */
+ public function deleteTask(Task $task): void;
+
+ /**
+ * @param int $id The id of the task
+ * @return Task
+ * @throws RuntimeException If the query failed
+ * @throws TaskNotFoundException If the task could not be found
+ * @since 28.0.0
+ */
+ public function getTask(int $id): Task;
+
+ /**
+ * @param int $id The id of the task
+ * @param string|null $userId The user id that scheduled the task
+ * @return Task
+ * @throws RuntimeException If the query failed
+ * @throws TaskNotFoundException If the task could not be found
+ * @since 28.0.0
+ */
+ public function getUserTask(int $id, ?string $userId): Task;
+
+ /**
+ * @param ?string $userId
+ * @param string $appId
+ * @param string|null $identifier
+ * @return Task[]
+ * @since 28.0.0
+ * @throws RuntimeException If the query failed
+ */
+ public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array;
+}
diff --git a/lib/public/TextToImage/IProvider.php b/lib/public/TextToImage/IProvider.php
new file mode 100644
index 00000000000..9f2ff51f599
--- /dev/null
+++ b/lib/public/TextToImage/IProvider.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\TextToImage;
+
+use RuntimeException;
+
+/**
+ * This is the interface that is implemented by apps that
+ * implement a text to image provider
+ * @since 28.0.0
+ */
+interface IProvider {
+ /**
+ * An arbitrary unique text string identifying this provider
+ * @since 28.0.0
+ */
+ public function getId(): string;
+
+ /**
+ * The localized name of this provider
+ * @since 28.0.0
+ */
+ public function getName(): string;
+
+ /**
+ * Processes a text
+ *
+ * @param string $prompt The input text
+ * @param resource[] $resources The file resources to write the images to
+ * @return void
+ * @since 28.0.0
+ * @throws RuntimeException If the text could not be processed
+ */
+ public function generate(string $prompt, array $resources): void;
+
+ /**
+ * The expected runtime for one task with this provider in seconds
+ * @since 28.0.0
+ */
+ public function getExpectedRuntime(): int;
+}
diff --git a/lib/public/TextToImage/IProviderWithUserId.php b/lib/public/TextToImage/IProviderWithUserId.php
new file mode 100644
index 00000000000..8afb0e56fbb
--- /dev/null
+++ b/lib/public/TextToImage/IProviderWithUserId.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCP\TextToImage;
+
+/**
+ * @since 29.0.0
+ */
+interface IProviderWithUserId extends IProvider {
+ /**
+ * @since 29.0.0
+ */
+ public function setUserId(?string $userId): void;
+}
diff --git a/lib/public/TextToImage/Task.php b/lib/public/TextToImage/Task.php
new file mode 100644
index 00000000000..e610af6aa96
--- /dev/null
+++ b/lib/public/TextToImage/Task.php
@@ -0,0 +1,212 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\TextToImage;
+
+use DateTime;
+use OCP\Files\AppData\IAppDataFactory;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\IImage;
+use OCP\Image;
+
+/**
+ * This is a text to image task
+ *
+ * @since 28.0.0
+ */
+final class Task implements \JsonSerializable {
+ protected ?int $id = null;
+
+ protected ?DateTime $completionExpectedAt = null;
+
+ /**
+ * @since 28.0.0
+ */
+ public const STATUS_FAILED = 4;
+ /**
+ * @since 28.0.0
+ */
+ public const STATUS_SUCCESSFUL = 3;
+ /**
+ * @since 28.0.0
+ */
+ public const STATUS_RUNNING = 2;
+ /**
+ * @since 28.0.0
+ */
+ public const STATUS_SCHEDULED = 1;
+ /**
+ * @since 28.0.0
+ */
+ public const STATUS_UNKNOWN = 0;
+
+ /**
+ * @psalm-var self::STATUS_*
+ */
+ protected int $status = self::STATUS_UNKNOWN;
+
+ /**
+ * @param string $input
+ * @param string $appId
+ * @param int $numberOfImages
+ * @param string|null $userId
+ * @param null|string $identifier An arbitrary identifier for this task. max length: 255 chars
+ * @since 28.0.0
+ */
+ final public function __construct(
+ protected string $input,
+ protected string $appId,
+ protected int $numberOfImages,
+ protected ?string $userId,
+ protected ?string $identifier = '',
+ ) {
+ }
+
+ /**
+ * @return IImage[]|null
+ * @since 28.0.0
+ */
+ final public function getOutputImages(): ?array {
+ $appData = \OCP\Server::get(IAppDataFactory::class)->get('core');
+ try {
+ $folder = $appData->getFolder('text2image')->getFolder((string)$this->getId());
+ $images = [];
+ for ($i = 0; $i < $this->getNumberOfImages(); $i++) {
+ $image = new Image();
+ $image->loadFromFileHandle($folder->getFile((string) $i)->read());
+ $images[] = $image;
+ }
+ return $images;
+ } catch (NotFoundException|NotPermittedException) {
+ return null;
+ }
+ }
+
+ /**
+ * @return int
+ * @since 28.0.0
+ */
+ final public function getNumberOfImages(): int {
+ return $this->numberOfImages;
+ }
+
+ /**
+ * @psalm-return self::STATUS_*
+ * @since 28.0.0
+ */
+ final public function getStatus(): int {
+ return $this->status;
+ }
+
+ /**
+ * @psalm-param self::STATUS_* $status
+ * @since 28.0.0
+ */
+ final public function setStatus(int $status): void {
+ $this->status = $status;
+ }
+
+ /**
+ * @param ?DateTime $at
+ * @since 28.0.0
+ */
+ final public function setCompletionExpectedAt(?DateTime $at): void {
+ $this->completionExpectedAt = $at;
+ }
+
+ /**
+ * @return ?DateTime
+ * @since 28.0.0
+ */
+ final public function getCompletionExpectedAt(): ?DateTime {
+ return $this->completionExpectedAt;
+ }
+
+ /**
+ * @return int|null
+ * @since 28.0.0
+ */
+ final public function getId(): ?int {
+ return $this->id;
+ }
+
+ /**
+ * @param int|null $id
+ * @since 28.0.0
+ */
+ final public function setId(?int $id): void {
+ $this->id = $id;
+ }
+
+ /**
+ * @return string
+ * @since 28.0.0
+ */
+ final public function getInput(): string {
+ return $this->input;
+ }
+
+ /**
+ * @return string
+ * @since 28.0.0
+ */
+ final public function getAppId(): string {
+ return $this->appId;
+ }
+
+ /**
+ * @return null|string
+ * @since 28.0.0
+ */
+ final public function getIdentifier(): ?string {
+ return $this->identifier;
+ }
+
+ /**
+ * @return string|null
+ * @since 28.0.0
+ */
+ final public function getUserId(): ?string {
+ return $this->userId;
+ }
+
+ /**
+ * @psalm-return array{id: ?int, status: self::STATUS_*, userId: ?string, appId: string, input: string, identifier: ?string, numberOfImages: int, completionExpectedAt: ?int}
+ * @since 28.0.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'id' => $this->getId(),
+ 'status' => $this->getStatus(),
+ 'userId' => $this->getUserId(),
+ 'appId' => $this->getAppId(),
+ 'numberOfImages' => $this->getNumberOfImages(),
+ 'input' => $this->getInput(),
+ 'identifier' => $this->getIdentifier(),
+ 'completionExpectedAt' => $this->getCompletionExpectedAt()->getTimestamp(),
+ ];
+ }
+}
diff --git a/lib/public/Translation/ITranslationProviderWithId.php b/lib/public/Translation/ITranslationProviderWithId.php
new file mode 100644
index 00000000000..fa08ef7cb17
--- /dev/null
+++ b/lib/public/Translation/ITranslationProviderWithId.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2024 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace OCP\Translation;
+
+/**
+ * @since 29.0.0
+ */
+interface ITranslationProviderWithId extends ITranslationProvider {
+ /**
+ * @since 29.0.0
+ */
+ public function getId(): string;
+}
diff --git a/lib/public/Translation/ITranslationProviderWithUserId.php b/lib/public/Translation/ITranslationProviderWithUserId.php
new file mode 100644
index 00000000000..9a573a8150e
--- /dev/null
+++ b/lib/public/Translation/ITranslationProviderWithUserId.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2024 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace OCP\Translation;
+
+/**
+ * @since 29.0.0
+ */
+interface ITranslationProviderWithUserId extends ITranslationProvider {
+ /**
+ * @param string|null $userId The userId of the user requesting the current task
+ * @since 29.0.0
+ */
+ public function setUserId(?string $userId);
+}
diff --git a/lib/public/User/Backend/IProvideEnabledStateBackend.php b/lib/public/User/Backend/IProvideEnabledStateBackend.php
index d03beacd7b8..f12d99fd1a6 100644
--- a/lib/public/User/Backend/IProvideEnabledStateBackend.php
+++ b/lib/public/User/Backend/IProvideEnabledStateBackend.php
@@ -52,5 +52,5 @@ interface IProvideEnabledStateBackend {
*
* @return string[]
*/
- public function getDisabledUserList(int $offset = 0, ?int $limit = null): array;
+ public function getDisabledUserList(?int $limit = null, int $offset = 0): array;
}
diff --git a/lib/public/User/Events/BeforePasswordUpdatedEvent.php b/lib/public/User/Events/BeforePasswordUpdatedEvent.php
index 11eb5ad9dd0..ee228ae01e7 100644
--- a/lib/public/User/Events/BeforePasswordUpdatedEvent.php
+++ b/lib/public/User/Events/BeforePasswordUpdatedEvent.php
@@ -51,8 +51,8 @@ class BeforePasswordUpdatedEvent extends Event {
* @since 18.0.0
*/
public function __construct(IUser $user,
- string $password,
- string $recoveryPassword = null) {
+ string $password,
+ string $recoveryPassword = null) {
parent::__construct();
$this->user = $user;
$this->password = $password;
diff --git a/lib/public/User/Events/BeforeUserCreatedEvent.php b/lib/public/User/Events/BeforeUserCreatedEvent.php
index 67e9177b34d..ee33239a12c 100644
--- a/lib/public/User/Events/BeforeUserCreatedEvent.php
+++ b/lib/public/User/Events/BeforeUserCreatedEvent.php
@@ -44,7 +44,7 @@ class BeforeUserCreatedEvent extends Event {
* @since 18.0.0
*/
public function __construct(string $uid,
- string $password) {
+ string $password) {
parent::__construct();
$this->uid = $uid;
$this->password = $password;
diff --git a/lib/public/User/Events/OutOfOfficeChangedEvent.php b/lib/public/User/Events/OutOfOfficeChangedEvent.php
new file mode 100644
index 00000000000..5e5753b7202
--- /dev/null
+++ b/lib/public/User/Events/OutOfOfficeChangedEvent.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\User\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\User\IOutOfOfficeData;
+
+/**
+ * Emitted when a user's out-of-office period has changed
+ *
+ * @since 28.0.0
+ */
+class OutOfOfficeChangedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(private IOutOfOfficeData $data) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getData(): IOutOfOfficeData {
+ return $this->data;
+ }
+}
diff --git a/lib/public/User/Events/OutOfOfficeClearedEvent.php b/lib/public/User/Events/OutOfOfficeClearedEvent.php
new file mode 100644
index 00000000000..48a77c77023
--- /dev/null
+++ b/lib/public/User/Events/OutOfOfficeClearedEvent.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\User\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\User\IOutOfOfficeData;
+
+/**
+ * Emitted when a user's out-of-office period is cleared
+ *
+ * @since 28.0.0
+ */
+class OutOfOfficeClearedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(private IOutOfOfficeData $data) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getData(): IOutOfOfficeData {
+ return $this->data;
+ }
+}
diff --git a/lib/public/User/Events/OutOfOfficeEndedEvent.php b/lib/public/User/Events/OutOfOfficeEndedEvent.php
new file mode 100644
index 00000000000..43a6bf77e28
--- /dev/null
+++ b/lib/public/User/Events/OutOfOfficeEndedEvent.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\User\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\User\IOutOfOfficeData;
+
+/**
+ * Emitted when a user's out-of-office period ended
+ *
+ * @since 28.0.0
+ */
+class OutOfOfficeEndedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(private IOutOfOfficeData $data) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getData(): IOutOfOfficeData {
+ return $this->data;
+ }
+}
diff --git a/lib/public/User/Events/OutOfOfficeScheduledEvent.php b/lib/public/User/Events/OutOfOfficeScheduledEvent.php
new file mode 100644
index 00000000000..2bcbec63478
--- /dev/null
+++ b/lib/public/User/Events/OutOfOfficeScheduledEvent.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\User\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\User\IOutOfOfficeData;
+
+/**
+ * Emitted when a user's out-of-office period is scheduled
+ *
+ * @since 28.0.0
+ */
+class OutOfOfficeScheduledEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(private IOutOfOfficeData $data) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getData(): IOutOfOfficeData {
+ return $this->data;
+ }
+}
diff --git a/lib/public/User/Events/OutOfOfficeStartedEvent.php b/lib/public/User/Events/OutOfOfficeStartedEvent.php
new file mode 100644
index 00000000000..f7816c968dd
--- /dev/null
+++ b/lib/public/User/Events/OutOfOfficeStartedEvent.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\User\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\User\IOutOfOfficeData;
+
+/**
+ * Emitted when a user's out-of-office period started
+ *
+ * @since 28.0.0
+ */
+class OutOfOfficeStartedEvent extends Event {
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(private IOutOfOfficeData $data) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function getData(): IOutOfOfficeData {
+ return $this->data;
+ }
+}
diff --git a/lib/public/User/Events/PasswordUpdatedEvent.php b/lib/public/User/Events/PasswordUpdatedEvent.php
index 41d510553b5..782d6d270ea 100644
--- a/lib/public/User/Events/PasswordUpdatedEvent.php
+++ b/lib/public/User/Events/PasswordUpdatedEvent.php
@@ -51,8 +51,8 @@ class PasswordUpdatedEvent extends Event {
* @since 18.0.0
*/
public function __construct(IUser $user,
- string $password,
- string $recoveryPassword = null) {
+ string $password,
+ string $recoveryPassword = null) {
parent::__construct();
$this->user = $user;
$this->password = $password;
diff --git a/lib/public/User/Events/UserChangedEvent.php b/lib/public/User/Events/UserChangedEvent.php
index f48dd3914e6..870b0326920 100644
--- a/lib/public/User/Events/UserChangedEvent.php
+++ b/lib/public/User/Events/UserChangedEvent.php
@@ -43,9 +43,9 @@ class UserChangedEvent extends Event {
* @since 18.0.0
*/
public function __construct(IUser $user,
- string $feature,
- $value,
- $oldValue = null) {
+ string $feature,
+ $value,
+ $oldValue = null) {
parent::__construct();
$this->user = $user;
$this->feature = $feature;
diff --git a/lib/public/User/Events/UserCreatedEvent.php b/lib/public/User/Events/UserCreatedEvent.php
index 7d343bfd5b8..b0a734be0cb 100644
--- a/lib/public/User/Events/UserCreatedEvent.php
+++ b/lib/public/User/Events/UserCreatedEvent.php
@@ -45,7 +45,7 @@ class UserCreatedEvent extends Event {
* @since 18.0.0
*/
public function __construct(IUser $user,
- string $password) {
+ string $password) {
parent::__construct();
$this->user = $user;
$this->password = $password;
diff --git a/lib/public/User/Events/UserLiveStatusEvent.php b/lib/public/User/Events/UserLiveStatusEvent.php
index d04c3b61e24..8b6207d685d 100644
--- a/lib/public/User/Events/UserLiveStatusEvent.php
+++ b/lib/public/User/Events/UserLiveStatusEvent.php
@@ -60,8 +60,8 @@ class UserLiveStatusEvent extends Event {
* @since 20.0.0
*/
public function __construct(IUser $user,
- string $status,
- int $timestamp) {
+ string $status,
+ int $timestamp) {
parent::__construct();
$this->user = $user;
$this->status = $status;
diff --git a/lib/public/User/IAvailabilityCoordinator.php b/lib/public/User/IAvailabilityCoordinator.php
new file mode 100644
index 00000000000..3a79e39b7b7
--- /dev/null
+++ b/lib/public/User/IAvailabilityCoordinator.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\User;
+
+use OCP\IUser;
+
+/**
+ * Coordinator for availability and out-of-office messages
+ *
+ * @since 28.0.0
+ */
+interface IAvailabilityCoordinator {
+ /**
+ * Check if the feature is enabled on this instance
+ *
+ * @return bool
+ *
+ * @since 28.0.0
+ */
+ public function isEnabled(): bool;
+
+ /**
+ * Get the user's out-of-office message, if any
+ *
+ * @since 28.0.0
+ */
+ public function getCurrentOutOfOfficeData(IUser $user): ?IOutOfOfficeData;
+
+ /**
+ * Reset the absence cache to null
+ *
+ * @since 28.0.0
+ */
+ public function clearCache(string $userId): void;
+
+ /**
+ * Is the absence in effect at this moment
+ *
+ * @param IOutOfOfficeData $data
+ * @return bool
+ * @since 28.0.0
+ */
+ public function isInEffect(IOutOfOfficeData $data): bool;
+}
diff --git a/lib/public/User/IOutOfOfficeData.php b/lib/public/User/IOutOfOfficeData.php
new file mode 100644
index 00000000000..31281104382
--- /dev/null
+++ b/lib/public/User/IOutOfOfficeData.php
@@ -0,0 +1,94 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\User;
+
+use JsonSerializable;
+use OCP\IUser;
+
+/**
+ * DTO to hold out-of-office information of a user
+ *
+ * @psalm-type OutOfOfficeData = array{
+ * id: string,
+ * userId: string,
+ * startDate: int,
+ * endDate: int,
+ * shortMessage: string,
+ * message: string,
+ * }
+ *
+ * @since 28.0.0
+ */
+interface IOutOfOfficeData extends JsonSerializable {
+ /**
+ * Get the unique token assigned to the current out-of-office event
+ *
+ * @since 28.0.0
+ */
+ public function getId(): string;
+
+ /**
+ * @since 28.0.0
+ */
+ public function getUser(): IUser;
+
+ /**
+ * Get the accurate out-of-office start date
+ *
+ * This event is not guaranteed to be emitted exactly at start date
+ *
+ * @since 28.0.0
+ */
+ public function getStartDate(): int;
+
+ /**
+ * Get the (preliminary) out-of-office end date
+ *
+ * @since 28.0.0
+ */
+ public function getEndDate(): int;
+
+ /**
+ * Get the short summary text displayed in the user status and similar
+ *
+ * @since 28.0.0
+ */
+ public function getShortMessage(): string;
+
+ /**
+ * Get the long out-of-office message for auto responders and similar
+ *
+ * @since 28.0.0
+ */
+ public function getMessage(): string;
+
+ /**
+ * @return OutOfOfficeData
+ *
+ * @since 28.0.0
+ */
+ public function jsonSerialize(): array;
+}
diff --git a/lib/public/UserMigration/IImportSource.php b/lib/public/UserMigration/IImportSource.php
index da2c87ba241..e9d49784f5d 100644
--- a/lib/public/UserMigration/IImportSource.php
+++ b/lib/public/UserMigration/IImportSource.php
@@ -32,6 +32,9 @@ use OCP\Files\Folder;
* @since 24.0.0
*/
interface IImportSource {
+ /**
+ * @since 24.0.0
+ */
public const PATH_USER = 'user.json';
/**
diff --git a/lib/public/UserStatus/IManager.php b/lib/public/UserStatus/IManager.php
index 9cc8eaad8ee..a85c1894c65 100644
--- a/lib/public/UserStatus/IManager.php
+++ b/lib/public/UserStatus/IManager.php
@@ -52,9 +52,11 @@ interface IManager {
* @param string $messageId The id of the predefined message.
* @param string $status The status to assign
* @param bool $createBackup If true, this will store the old status so that it is possible to revert it later (e.g. after a call).
+ * @param string|null $customMessage
* @since 23.0.0
+ * @since 28.0.0 Optional parameter $customMessage was added
*/
- public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup = false): void;
+ public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup = false, ?string $customMessage = null): void;
/**
* Revert an automatically set user status. For example after leaving a call,
diff --git a/lib/public/UserStatus/IUserStatus.php b/lib/public/UserStatus/IUserStatus.php
index 74c54cc9da2..f167f9a82ee 100644
--- a/lib/public/UserStatus/IUserStatus.php
+++ b/lib/public/UserStatus/IUserStatus.php
@@ -53,6 +53,12 @@ interface IUserStatus {
/**
* @var string
+ * @since 28.0.0
+ */
+ public const BUSY = 'busy';
+
+ /**
+ * @var string
* @since 20.0.0
*/
public const OFFLINE = 'offline';
@@ -76,6 +82,30 @@ interface IUserStatus {
public const MESSAGE_AVAILABILITY = 'availability';
/**
+ * @var string
+ * @since 28.0.1
+ */
+ public const MESSAGE_OUT_OF_OFFICE = 'out-of-office';
+
+ /**
+ * @var string
+ * @since 28.0.0
+ */
+ public const MESSAGE_VACATION = 'vacationing';
+
+ /**
+ * @var string
+ * @since 28.0.0
+ */
+ public const MESSAGE_CALENDAR_BUSY = 'meeting';
+
+ /**
+ * @var string
+ * @since 28.0.0
+ */
+ public const MESSAGE_CALENDAR_BUSY_TENTATIVE = 'busy-tentative';
+
+ /**
* Get the user this status is connected to
*
* @return string
diff --git a/lib/public/Util.php b/lib/public/Util.php
index 34ccc61074f..87b0700f12b 100644
--- a/lib/public/Util.php
+++ b/lib/public/Util.php
@@ -46,11 +46,13 @@
namespace OCP;
+use bantu\IniGetWrapper\IniGetWrapper;
use OC\AppScriptDependency;
use OC\AppScriptSort;
use OCP\Share\IManager as IShareManager;
-use bantu\IniGetWrapper\IniGetWrapper;
+use OCP\Share\IManager;
use Psr\Container\ContainerExceptionInterface;
+use Psr\Log\LoggerInterface;
/**
* This class provides different helper functions to make the life of a developer easier
@@ -58,17 +60,11 @@ use Psr\Container\ContainerExceptionInterface;
* @since 4.0.0
*/
class Util {
- /** @var \OCP\Share\IManager */
- private static $shareManager;
-
- /** @var array */
- private static $scripts = [];
+ private static ?IManager $shareManager = null;
- /** @var array */
- private static $scriptDeps = [];
-
- /** @var array */
- private static $sortedScriptDeps = [];
+ private static array $scriptsInit = [];
+ private static array $scripts = [];
+ private static array $scriptDeps = [];
/**
* get the current installed version of Nextcloud
@@ -111,19 +107,6 @@ class Util {
}
/**
- * write a message in the log
- * @param string $app
- * @param string $message
- * @param int $level
- * @since 4.0.0
- * @deprecated 13.0.0 use log of \OCP\ILogger
- */
- public static function writeLog($app, $message, $level) {
- $context = ['app' => $app];
- \OC::$server->getLogger()->log($level, $message, $context);
- }
-
- /**
* check if sharing is disabled for the current user
*
* @return boolean
@@ -145,13 +128,10 @@ class Util {
/**
* get l10n object
- * @param string $application
- * @param string|null $language
- * @return \OCP\IL10N
* @since 6.0.0 - parameter $language was added in 8.0.0
*/
- public static function getL10N($application, $language = null) {
- return \OC::$server->getL10N($application, $language);
+ public static function getL10N(string $application, ?string $language = null): IL10N {
+ return Server::get(\OCP\L10N\IFactory::class)->get($application, $language);
}
/**
@@ -165,6 +145,31 @@ class Util {
}
/**
+ * Add a standalone init js file that is loaded for initialization
+ *
+ * Be careful loading scripts using this method as they are loaded early
+ * and block the initial page rendering. They should not have dependencies
+ * on any other scripts than core-common and core-main.
+ *
+ * @since 28.0.0
+ */
+ public static function addInitScript(string $application, string $file): void {
+ if (!empty($application)) {
+ $path = "$application/js/$file";
+ } else {
+ $path = "js/$file";
+ }
+
+ // We need to handle the translation BEFORE the init script
+ // is loaded, as the init script might use translations
+ if ($application !== 'core' && !str_contains($file, 'l10n')) {
+ self::addTranslations($application, null, true);
+ }
+
+ self::$scriptsInit[] = $path;
+ }
+
+ /**
* add a javascript file
*
* @param string $application
@@ -215,7 +220,8 @@ class Util {
$sortedScripts = $scriptSort->sort(self::$scripts, self::$scriptDeps);
// Flatten array and remove duplicates
- $sortedScripts = $sortedScripts ? array_merge(...array_values(($sortedScripts))) : [];
+ $sortedScripts = array_merge([self::$scriptsInit], $sortedScripts);
+ $sortedScripts = array_merge(...array_values($sortedScripts));
// Override core-common and core-main order
if (in_array('core/js/main', $sortedScripts)) {
@@ -232,9 +238,10 @@ class Util {
* Add a translation JS file
* @param string $application application id
* @param string $languageCode language code, defaults to the current locale
+ * @param bool $init whether the translations should be loaded early or not
* @since 8.0.0
*/
- public static function addTranslations($application, $languageCode = null) {
+ public static function addTranslations($application, $languageCode = null, $init = false) {
if (is_null($languageCode)) {
$languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
}
@@ -243,7 +250,12 @@ class Util {
} else {
$path = "l10n/$languageCode";
}
- self::$scripts[$application][] = $path;
+
+ if ($init) {
+ self::$scriptsInit[] = $path;
+ } else {
+ self::$scripts[$application][] = $path;
+ }
}
/**
@@ -511,10 +523,31 @@ class Util {
}
/**
+ * Get a list of characters forbidden in file names
+ * @return string[]
+ * @since 29.0.0
+ */
+ public static function getForbiddenFileNameChars(): array {
+ // Get always forbidden characters
+ $invalidChars = str_split(\OCP\Constants::FILENAME_INVALID_CHARS);
+ if ($invalidChars === false) {
+ $invalidChars = [];
+ }
+
+ // Get admin defined invalid characters
+ $additionalChars = \OCP\Server::get(IConfig::class)->getSystemValue('forbidden_chars', []);
+ if (!is_array($additionalChars)) {
+ \OCP\Server::get(LoggerInterface::class)->error('Invalid system config value for "forbidden_chars" is ignored.');
+ $additionalChars = [];
+ }
+ return array_merge($invalidChars, $additionalChars);
+ }
+
+ /**
* Returns whether the given file name is valid
* @param string $file file name to check
* @return bool true if the file name is valid, false otherwise
- * @deprecated 8.1.0 use \OC\Files\View::verifyPath()
+ * @deprecated 8.1.0 use OCP\Files\Storage\IStorage::verifyPath()
* @since 7.0.0
* @suppress PhanDeprecatedFunction
*/
diff --git a/lib/public/WorkflowEngine/IManager.php b/lib/public/WorkflowEngine/IManager.php
index abdcdfa107a..83e2b69dc65 100644
--- a/lib/public/WorkflowEngine/IManager.php
+++ b/lib/public/WorkflowEngine/IManager.php
@@ -31,7 +31,14 @@ namespace OCP\WorkflowEngine;
* @since 9.1
*/
interface IManager {
+ /**
+ * @since 18.0.0
+ */
public const SCOPE_ADMIN = 0;
+
+ /**
+ * @since 18.0.0
+ */
public const SCOPE_USER = 1;
/**