aboutsummaryrefslogtreecommitdiffstats
path: root/apps/provisioning_api
diff options
context:
space:
mode:
Diffstat (limited to 'apps/provisioning_api')
-rw-r--r--apps/provisioning_api/appinfo/info.xml32
-rw-r--r--apps/provisioning_api/appinfo/routes.php59
-rw-r--r--apps/provisioning_api/composer/autoload.php18
-rw-r--r--apps/provisioning_api/composer/composer.lock18
-rw-r--r--apps/provisioning_api/composer/composer/ClassLoader.php208
-rw-r--r--apps/provisioning_api/composer/composer/InstalledVersions.php359
-rw-r--r--apps/provisioning_api/composer/composer/autoload_classmap.php10
-rw-r--r--apps/provisioning_api/composer/composer/autoload_namespaces.php2
-rw-r--r--apps/provisioning_api/composer/composer/autoload_psr4.php2
-rw-r--r--apps/provisioning_api/composer/composer/autoload_real.php18
-rw-r--r--apps/provisioning_api/composer/composer/autoload_static.php8
-rw-r--r--apps/provisioning_api/composer/composer/installed.json5
-rw-r--r--apps/provisioning_api/composer/composer/installed.php23
-rw-r--r--apps/provisioning_api/img/app.svg2
-rw-r--r--apps/provisioning_api/l10n/.gitkeep0
-rw-r--r--apps/provisioning_api/l10n/ar.js43
-rw-r--r--apps/provisioning_api/l10n/ar.json41
-rw-r--r--apps/provisioning_api/l10n/ast.js40
-rw-r--r--apps/provisioning_api/l10n/ast.json38
-rw-r--r--apps/provisioning_api/l10n/ca.js43
-rw-r--r--apps/provisioning_api/l10n/ca.json41
-rw-r--r--apps/provisioning_api/l10n/cs.js44
-rw-r--r--apps/provisioning_api/l10n/cs.json42
-rw-r--r--apps/provisioning_api/l10n/da.js43
-rw-r--r--apps/provisioning_api/l10n/da.json41
-rw-r--r--apps/provisioning_api/l10n/de.js44
-rw-r--r--apps/provisioning_api/l10n/de.json42
-rw-r--r--apps/provisioning_api/l10n/de_DE.js44
-rw-r--r--apps/provisioning_api/l10n/de_DE.json42
-rw-r--r--apps/provisioning_api/l10n/en_GB.js44
-rw-r--r--apps/provisioning_api/l10n/en_GB.json42
-rw-r--r--apps/provisioning_api/l10n/es.js41
-rw-r--r--apps/provisioning_api/l10n/es.json39
-rw-r--r--apps/provisioning_api/l10n/es_MX.js42
-rw-r--r--apps/provisioning_api/l10n/es_MX.json40
-rw-r--r--apps/provisioning_api/l10n/et_EE.js41
-rw-r--r--apps/provisioning_api/l10n/et_EE.json39
-rw-r--r--apps/provisioning_api/l10n/eu.js43
-rw-r--r--apps/provisioning_api/l10n/eu.json41
-rw-r--r--apps/provisioning_api/l10n/fr.js43
-rw-r--r--apps/provisioning_api/l10n/fr.json41
-rw-r--r--apps/provisioning_api/l10n/ga.js44
-rw-r--r--apps/provisioning_api/l10n/ga.json42
-rw-r--r--apps/provisioning_api/l10n/gl.js43
-rw-r--r--apps/provisioning_api/l10n/gl.json41
-rw-r--r--apps/provisioning_api/l10n/ja.js44
-rw-r--r--apps/provisioning_api/l10n/ja.json42
-rw-r--r--apps/provisioning_api/l10n/nb.js42
-rw-r--r--apps/provisioning_api/l10n/nb.json40
-rw-r--r--apps/provisioning_api/l10n/pl.js44
-rw-r--r--apps/provisioning_api/l10n/pl.json42
-rw-r--r--apps/provisioning_api/l10n/pt_BR.js44
-rw-r--r--apps/provisioning_api/l10n/pt_BR.json42
-rw-r--r--apps/provisioning_api/l10n/ru.js44
-rw-r--r--apps/provisioning_api/l10n/ru.json42
-rw-r--r--apps/provisioning_api/l10n/sk.js43
-rw-r--r--apps/provisioning_api/l10n/sk.json41
-rw-r--r--apps/provisioning_api/l10n/sr.js43
-rw-r--r--apps/provisioning_api/l10n/sr.json41
-rw-r--r--apps/provisioning_api/l10n/sv.js28
-rw-r--r--apps/provisioning_api/l10n/sv.json26
-rw-r--r--apps/provisioning_api/l10n/sw.js44
-rw-r--r--apps/provisioning_api/l10n/sw.json42
-rw-r--r--apps/provisioning_api/l10n/tr.js43
-rw-r--r--apps/provisioning_api/l10n/tr.json41
-rw-r--r--apps/provisioning_api/l10n/ug.js43
-rw-r--r--apps/provisioning_api/l10n/ug.json41
-rw-r--r--apps/provisioning_api/l10n/uk.js44
-rw-r--r--apps/provisioning_api/l10n/uk.json42
-rw-r--r--apps/provisioning_api/l10n/zh_CN.js44
-rw-r--r--apps/provisioning_api/l10n/zh_CN.json42
-rw-r--r--apps/provisioning_api/l10n/zh_HK.js44
-rw-r--r--apps/provisioning_api/l10n/zh_HK.json42
-rw-r--r--apps/provisioning_api/l10n/zh_TW.js44
-rw-r--r--apps/provisioning_api/l10n/zh_TW.json42
-rw-r--r--apps/provisioning_api/lib/AppInfo/Application.php98
-rw-r--r--apps/provisioning_api/lib/Capabilities.php54
-rw-r--r--apps/provisioning_api/lib/Controller/AUserDataOCSController.php325
-rw-r--r--apps/provisioning_api/lib/Controller/AppConfigController.php225
-rw-r--r--apps/provisioning_api/lib/Controller/AppsController.php152
-rw-r--r--apps/provisioning_api/lib/Controller/GroupsController.php356
-rw-r--r--apps/provisioning_api/lib/Controller/PreferencesController.php201
-rw-r--r--apps/provisioning_api/lib/Controller/UsersController.php1836
-rw-r--r--apps/provisioning_api/lib/Controller/VerificationController.php125
-rw-r--r--apps/provisioning_api/lib/FederatedShareProviderFactory.php24
-rw-r--r--apps/provisioning_api/lib/Listener/UserDeletedListener.php40
-rw-r--r--apps/provisioning_api/lib/Middleware/Exceptions/NotSubAdminException.php27
-rw-r--r--apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php51
-rw-r--r--apps/provisioning_api/lib/ResponseDefinitions.php86
-rw-r--r--apps/provisioning_api/openapi-administration.json1803
-rw-r--r--apps/provisioning_api/openapi-administration.json.license2
-rw-r--r--apps/provisioning_api/openapi-full.json4890
-rw-r--r--apps/provisioning_api/openapi-full.json.license2
-rw-r--r--apps/provisioning_api/openapi.json3463
-rw-r--r--apps/provisioning_api/openapi.json.license2
-rw-r--r--apps/provisioning_api/tests/CapabilitiesTest.php77
-rw-r--r--apps/provisioning_api/tests/Controller/AppConfigControllerTest.php312
-rw-r--r--apps/provisioning_api/tests/Controller/AppsControllerTest.php107
-rw-r--r--apps/provisioning_api/tests/Controller/GroupsControllerTest.php402
-rw-r--r--apps/provisioning_api/tests/Controller/UsersControllerTest.php3251
-rw-r--r--apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php86
-rw-r--r--apps/provisioning_api/tests/TestCase.php43
102 files changed, 18984 insertions, 2320 deletions
diff --git a/apps/provisioning_api/appinfo/info.xml b/apps/provisioning_api/appinfo/info.xml
index 849e74432f0..68d36845354 100644
--- a/apps/provisioning_api/appinfo/info.xml
+++ b/apps/provisioning_api/appinfo/info.xml
@@ -1,28 +1,36 @@
-<?xml version="1.0"?>
-<info>
+<?xml version="1.0"?>
+<!--
+ - SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-FileCopyrightText: 2014-2016 owncloud, Inc.
+ - SPDX-License-Identifier: AGPL-3.0-only
+-->
+<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>provisioning_api</id>
<name>Provisioning API</name>
+ <summary>This application enables a set of APIs that external systems can use to manage accounts, groups and apps.</summary>
<description>
- This application enables a set of APIs that external systems can use to create, edit, delete and query user
- attributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin users
+ This application enables a set of APIs that external systems can use to create, edit, delete and query account
+ attributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts
can also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables
an admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.
- Once the app is enabled, http requests can be used via a Basic Auth header to perform any of the functions
+ Once the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions
listed above. More information is available in the Provisioning API documentation, including example calls
and server responses.
</description>
- <licence>AGPL</licence>
+ <version>1.22.0</version>
+ <licence>agpl</licence>
<author>Tom Needham</author>
- <default_enable/>
- <documentation>
- <admin>admin-provisioning-api</admin>
- </documentation>
- <version>1.4.0</version>
<namespace>Provisioning_API</namespace>
<types>
<prevent_group_restriction/>
</types>
+ <documentation>
+ <admin>admin-provisioning-api</admin>
+ </documentation>
+ <category>integration</category>
+ <bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies>
- <nextcloud min-version="14" max-version="14" />
+ <nextcloud min-version="32" max-version="32"/>
</dependencies>
</info>
diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php
index c4932ebb28b..df4f806fa08 100644
--- a/apps/provisioning_api/appinfo/routes.php
+++ b/apps/provisioning_api/appinfo/routes.php
@@ -1,29 +1,10 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
return [
'ocs' => [
// Apps
@@ -34,24 +15,39 @@ return [
// Groups
['root' => '/cloud', 'name' => 'Groups#getGroups', 'url' => '/groups', 'verb' => 'GET'],
- ['root' => '/cloud', 'name' => 'Groups#getGroup', 'url' => '/groups/{groupId}', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Groups#getGroupsDetails', 'url' => '/groups/details', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Groups#getGroupUsers', 'url' => '/groups/{groupId}/users', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
+ ['root' => '/cloud', 'name' => 'Groups#getGroupUsersDetails', 'url' => '/groups/{groupId}/users/details', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
+ ['root' => '/cloud', 'name' => 'Groups#getSubAdminsOfGroup', 'url' => '/groups/{groupId}/subadmins', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
['root' => '/cloud', 'name' => 'Groups#addGroup', 'url' => '/groups', 'verb' => 'POST'],
- ['root' => '/cloud', 'name' => 'Groups#deleteGroup', 'url' => '/groups/{groupId}', 'verb' => 'DELETE'],
- ['root' => '/cloud', 'name' => 'Groups#getSubAdminsOfGroup', 'url' => '/groups/{groupId}/subadmins', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Groups#getGroup', 'url' => '/groups/{groupId}', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
+ ['root' => '/cloud', 'name' => 'Groups#updateGroup', 'url' => '/groups/{groupId}', 'verb' => 'PUT', 'requirements' => ['groupId' => '.+']],
+ ['root' => '/cloud', 'name' => 'Groups#deleteGroup', 'url' => '/groups/{groupId}', 'verb' => 'DELETE', 'requirements' => ['groupId' => '.+']],
// Users
['root' => '/cloud', 'name' => 'Users#getUsers', 'url' => '/users', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getUsersDetails', 'url' => '/users/details', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getDisabledUsersDetails', 'url' => '/users/disabled', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getLastLoggedInUsers', 'url' => '/users/recent', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#searchByPhoneNumbers', 'url' => '/users/search/by-phone', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#addUser', 'url' => '/users', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#getUser', 'url' => '/users/{userId}', 'verb' => 'GET'],
['root' => '/cloud', 'name' => 'Users#getCurrentUser', 'url' => '/user', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getEditableFields', 'url' => '/user/fields', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getEditableFieldsForUser', 'url' => '/user/fields/{userId}', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getEnabledApps', 'url' => '/user/apps', 'verb' => 'GET'],
['root' => '/cloud', 'name' => 'Users#editUser', 'url' => '/users/{userId}', 'verb' => 'PUT'],
+ ['root' => '/cloud', 'name' => 'Users#editUserMultiValue', 'url' => '/users/{userId}/{collectionName}', 'verb' => 'PUT', 'requirements' => ['collectionName' => '^(?!enable$|disable$)[a-zA-Z0-9_]*$']],
+ ['root' => '/cloud', 'name' => 'Users#wipeUserDevices', 'url' => '/users/{userId}/wipe', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#deleteUser', 'url' => '/users/{userId}', 'verb' => 'DELETE'],
['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'],
['root' => '/cloud', 'name' => 'Users#disableUser', 'url' => '/users/{userId}/disable', 'verb' => 'PUT'],
['root' => '/cloud', 'name' => 'Users#getUsersGroups', 'url' => '/users/{userId}/groups', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getUsersGroupsDetails', 'url' => '/users/{userId}/groups/details', 'verb' => 'GET'],
['root' => '/cloud', 'name' => 'Users#addToGroup', 'url' => '/users/{userId}/groups', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#removeFromGroup', 'url' => '/users/{userId}/groups', 'verb' => 'DELETE'],
['root' => '/cloud', 'name' => 'Users#getUserSubAdminGroups', 'url' => '/users/{userId}/subadmins', 'verb' => 'GET'],
+ ['root' => '/cloud', 'name' => 'Users#getUserSubAdminGroupsDetails', 'url' => '/users/{userId}/subadmins/details', 'verb' => 'GET'],
['root' => '/cloud', 'name' => 'Users#addSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#removeSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'DELETE'],
['root' => '/cloud', 'name' => 'Users#resendWelcomeMessage', 'url' => '/users/{userId}/welcome', 'verb' => 'POST'],
@@ -62,5 +58,16 @@ return [
['name' => 'AppConfig#getValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'GET'],
['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'],
['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'],
+
+ // Preferences
+ ['name' => 'Preferences#setPreference', 'url' => '/api/v1/config/users/{appId}/{configKey}', 'verb' => 'POST'],
+ ['name' => 'Preferences#setMultiplePreferences', 'url' => '/api/v1/config/users/{appId}', 'verb' => 'POST'],
+ ['name' => 'Preferences#deletePreference', 'url' => '/api/v1/config/users/{appId}/{configKey}', 'verb' => 'DELETE'],
+ ['name' => 'Preferences#deleteMultiplePreference', 'url' => '/api/v1/config/users/{appId}', 'verb' => 'DELETE'],
],
+ 'routes' => [
+ // Verification
+ ['name' => 'Verification#showVerifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'GET'],
+ ['name' => 'Verification#verifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'POST'],
+ ]
];
diff --git a/apps/provisioning_api/composer/autoload.php b/apps/provisioning_api/composer/autoload.php
index 9734ee42b19..539f62b3fe5 100644
--- a/apps/provisioning_api/composer/autoload.php
+++ b/apps/provisioning_api/composer/autoload.php
@@ -2,6 +2,24 @@
// autoload.php @generated by Composer
+if (PHP_VERSION_ID < 50600) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, $err);
+ } elseif (!headers_sent()) {
+ echo $err;
+ }
+ }
+ trigger_error(
+ $err,
+ E_USER_ERROR
+ );
+}
+
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitProvisioning_API::getLoader();
diff --git a/apps/provisioning_api/composer/composer.lock b/apps/provisioning_api/composer/composer.lock
new file mode 100644
index 00000000000..fd0bcbcb753
--- /dev/null
+++ b/apps/provisioning_api/composer/composer.lock
@@ -0,0 +1,18 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "d751713988987e9331980363e24189ce",
+ "packages": [],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.1.0"
+}
diff --git a/apps/provisioning_api/composer/composer/ClassLoader.php b/apps/provisioning_api/composer/composer/ClassLoader.php
index dc02dfb114f..7824d8f7eaf 100644
--- a/apps/provisioning_api/composer/composer/ClassLoader.php
+++ b/apps/provisioning_api/composer/composer/ClassLoader.php
@@ -37,57 +37,126 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
- * @see http://www.php-fig.org/psr/psr-0/
- * @see http://www.php-fig.org/psr/psr-4/
+ * @see https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
+ /** @var \Closure(string):void */
+ private static $includeFile;
+
+ /** @var string|null */
+ private $vendorDir;
+
// PSR-4
+ /**
+ * @var array<string, array<string, int>>
+ */
private $prefixLengthsPsr4 = array();
+ /**
+ * @var array<string, list<string>>
+ */
private $prefixDirsPsr4 = array();
+ /**
+ * @var list<string>
+ */
private $fallbackDirsPsr4 = array();
// PSR-0
+ /**
+ * List of PSR-0 prefixes
+ *
+ * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
+ *
+ * @var array<string, array<string, list<string>>>
+ */
private $prefixesPsr0 = array();
+ /**
+ * @var list<string>
+ */
private $fallbackDirsPsr0 = array();
+ /** @var bool */
private $useIncludePath = false;
+
+ /**
+ * @var array<string, string>
+ */
private $classMap = array();
+
+ /** @var bool */
private $classMapAuthoritative = false;
+
+ /**
+ * @var array<string, bool>
+ */
private $missingClasses = array();
+
+ /** @var string|null */
private $apcuPrefix;
+ /**
+ * @var array<string, self>
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param string|null $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ self::initializeIncludeClosure();
+ }
+
+ /**
+ * @return array<string, list<string>>
+ */
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
- return call_user_func_array('array_merge', $this->prefixesPsr0);
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
+ /**
+ * @return array<string, list<string>>
+ */
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
+ /**
+ * @return list<string>
+ */
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
+ /**
+ * @return list<string>
+ */
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
+ /**
+ * @return array<string, string> Array of classname => path
+ */
public function getClassMap()
{
return $this->classMap;
}
/**
- * @param array $classMap Class to filename map
+ * @param array<string, string> $classMap Class to filename map
+ *
+ * @return void
*/
public function addClassMap(array $classMap)
{
@@ -102,22 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
- * @param string $prefix The prefix
- * @param array|string $paths The PSR-0 root directories
- * @param bool $prepend Whether to prepend the directories
+ * @param string $prefix The prefix
+ * @param list<string>|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
*/
public function add($prefix, $paths, $prepend = false)
{
+ $paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
- (array) $paths,
+ $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
- (array) $paths
+ $paths
);
}
@@ -126,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
- $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+ $this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
- (array) $paths,
+ $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
- (array) $paths
+ $paths
);
}
}
@@ -147,25 +219,28 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param array|string $paths The PSR-4 base directories
- * @param bool $prepend Whether to prepend the directories
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param list<string>|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
+ *
+ * @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
+ $paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
- (array) $paths,
+ $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
- (array) $paths
+ $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -175,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
- $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ $this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
- (array) $paths,
+ $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
- (array) $paths
+ $paths
);
}
}
@@ -195,8 +270,10 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
- * @param string $prefix The prefix
- * @param array|string $paths The PSR-0 base directories
+ * @param string $prefix The prefix
+ * @param list<string>|string $paths The PSR-0 base directories
+ *
+ * @return void
*/
public function set($prefix, $paths)
{
@@ -211,10 +288,12 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param array|string $paths The PSR-4 base directories
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
+ *
+ * @return void
*/
public function setPsr4($prefix, $paths)
{
@@ -234,6 +313,8 @@ class ClassLoader
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
+ *
+ * @return void
*/
public function setUseIncludePath($useIncludePath)
{
@@ -256,6 +337,8 @@ class ClassLoader
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
+ *
+ * @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
@@ -276,10 +359,12 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
+ *
+ * @return void
*/
public function setApcuPrefix($apcuPrefix)
{
- $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
@@ -296,33 +381,55 @@ class ClassLoader
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
}
/**
* Unregisters this instance as an autoloader.
+ *
+ * @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
- * @return bool|null True if loaded, null otherwise
+ * @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
- includeFile($file);
+ $includeFile = self::$includeFile;
+ $includeFile($file);
return true;
}
+
+ return null;
}
/**
@@ -367,6 +474,21 @@ class ClassLoader
return $file;
}
+ /**
+ * Returns the currently registered loaders keyed by their corresponding vendor directories.
+ *
+ * @return array<string, self>
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
@@ -377,7 +499,7 @@ class ClassLoader
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
- $search = $subPath.'\\';
+ $search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
@@ -432,14 +554,26 @@ class ClassLoader
return false;
}
-}
-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- */
-function includeFile($file)
-{
- include $file;
+ /**
+ * @return void
+ */
+ private static function initializeIncludeClosure()
+ {
+ if (self::$includeFile !== null) {
+ return;
+ }
+
+ /**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ */
+ self::$includeFile = \Closure::bind(static function($file) {
+ include $file;
+ }, null, null);
+ }
}
diff --git a/apps/provisioning_api/composer/composer/InstalledVersions.php b/apps/provisioning_api/composer/composer/InstalledVersions.php
new file mode 100644
index 00000000000..51e734a774b
--- /dev/null
+++ b/apps/provisioning_api/composer/composer/InstalledVersions.php
@@ -0,0 +1,359 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+ /**
+ * @var mixed[]|null
+ * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
+ */
+ private static $installed;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+ */
+ private static $installedByVendor = array();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints((string) $constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
+ */
+ public static function getRootPackage()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+ * @return array[]
+ * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
+ */
+ public static function getRawData()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
+ *
+ * @return array[]
+ * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+ */
+ public static function getAllRawData()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
+ */
+ public static function reload($data)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+ */
+ private static function getInstalled()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+
+ if (self::$canGetVendors) {
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+ $required = require $vendorDir.'/composer/installed.php';
+ $installed[] = self::$installedByVendor[$vendorDir] = $required;
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+ self::$installed = $installed[count($installed) - 1];
+ }
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+ $required = require __DIR__ . '/installed.php';
+ self::$installed = $required;
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ if (self::$installed !== array()) {
+ $installed[] = self::$installed;
+ }
+
+ return $installed;
+ }
+}
diff --git a/apps/provisioning_api/composer/composer/autoload_classmap.php b/apps/provisioning_api/composer/composer/autoload_classmap.php
index 1ae8ef27d03..7a007f4577d 100644
--- a/apps/provisioning_api/composer/composer/autoload_classmap.php
+++ b/apps/provisioning_api/composer/composer/autoload_classmap.php
@@ -2,15 +2,23 @@
// autoload_classmap.php @generated by Composer
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
$baseDir = $vendorDir;
return array(
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'OCA\\Provisioning_API\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
+ 'OCA\\Provisioning_API\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
+ 'OCA\\Provisioning_API\\Controller\\AUserDataOCSController' => $baseDir . '/../lib/Controller/AUserDataOCSController.php',
'OCA\\Provisioning_API\\Controller\\AppConfigController' => $baseDir . '/../lib/Controller/AppConfigController.php',
'OCA\\Provisioning_API\\Controller\\AppsController' => $baseDir . '/../lib/Controller/AppsController.php',
'OCA\\Provisioning_API\\Controller\\GroupsController' => $baseDir . '/../lib/Controller/GroupsController.php',
+ 'OCA\\Provisioning_API\\Controller\\PreferencesController' => $baseDir . '/../lib/Controller/PreferencesController.php',
'OCA\\Provisioning_API\\Controller\\UsersController' => $baseDir . '/../lib/Controller/UsersController.php',
+ 'OCA\\Provisioning_API\\Controller\\VerificationController' => $baseDir . '/../lib/Controller/VerificationController.php',
+ 'OCA\\Provisioning_API\\FederatedShareProviderFactory' => $baseDir . '/../lib/FederatedShareProviderFactory.php',
+ 'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php',
'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => $baseDir . '/../lib/Middleware/Exceptions/NotSubAdminException.php',
'OCA\\Provisioning_API\\Middleware\\ProvisioningApiMiddleware' => $baseDir . '/../lib/Middleware/ProvisioningApiMiddleware.php',
+ 'OCA\\Provisioning_API\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
);
diff --git a/apps/provisioning_api/composer/composer/autoload_namespaces.php b/apps/provisioning_api/composer/composer/autoload_namespaces.php
index 71c9e91858d..3f5c9296251 100644
--- a/apps/provisioning_api/composer/composer/autoload_namespaces.php
+++ b/apps/provisioning_api/composer/composer/autoload_namespaces.php
@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
$baseDir = $vendorDir;
return array(
diff --git a/apps/provisioning_api/composer/composer/autoload_psr4.php b/apps/provisioning_api/composer/composer/autoload_psr4.php
index 46b5eb003d5..8b0d5ece1ad 100644
--- a/apps/provisioning_api/composer/composer/autoload_psr4.php
+++ b/apps/provisioning_api/composer/composer/autoload_psr4.php
@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
$baseDir = $vendorDir;
return array(
diff --git a/apps/provisioning_api/composer/composer/autoload_real.php b/apps/provisioning_api/composer/composer/autoload_real.php
index 33867a60f69..a3b1fdeb247 100644
--- a/apps/provisioning_api/composer/composer/autoload_real.php
+++ b/apps/provisioning_api/composer/composer/autoload_real.php
@@ -13,6 +13,9 @@ class ComposerAutoloaderInitProvisioning_API
}
}
+ /**
+ * @return \Composer\Autoload\ClassLoader
+ */
public static function getLoader()
{
if (null !== self::$loader) {
@@ -20,20 +23,11 @@ class ComposerAutoloaderInitProvisioning_API
}
spl_autoload_register(array('ComposerAutoloaderInitProvisioning_API', 'loadClassLoader'), true, true);
- self::$loader = $loader = new \Composer\Autoload\ClassLoader();
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitProvisioning_API', 'loadClassLoader'));
- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
- if ($useStaticLoader) {
- require_once __DIR__ . '/autoload_static.php';
-
- call_user_func(\Composer\Autoload\ComposerStaticInitProvisioning_API::getInitializer($loader));
- } else {
- $classMap = require __DIR__ . '/autoload_classmap.php';
- if ($classMap) {
- $loader->addClassMap($classMap);
- }
- }
+ require __DIR__ . '/autoload_static.php';
+ call_user_func(\Composer\Autoload\ComposerStaticInitProvisioning_API::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
diff --git a/apps/provisioning_api/composer/composer/autoload_static.php b/apps/provisioning_api/composer/composer/autoload_static.php
index 950a851eae9..9480fc2d3f1 100644
--- a/apps/provisioning_api/composer/composer/autoload_static.php
+++ b/apps/provisioning_api/composer/composer/autoload_static.php
@@ -21,13 +21,21 @@ class ComposerStaticInitProvisioning_API
);
public static $classMap = array (
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'OCA\\Provisioning_API\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
+ 'OCA\\Provisioning_API\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
+ 'OCA\\Provisioning_API\\Controller\\AUserDataOCSController' => __DIR__ . '/..' . '/../lib/Controller/AUserDataOCSController.php',
'OCA\\Provisioning_API\\Controller\\AppConfigController' => __DIR__ . '/..' . '/../lib/Controller/AppConfigController.php',
'OCA\\Provisioning_API\\Controller\\AppsController' => __DIR__ . '/..' . '/../lib/Controller/AppsController.php',
'OCA\\Provisioning_API\\Controller\\GroupsController' => __DIR__ . '/..' . '/../lib/Controller/GroupsController.php',
+ 'OCA\\Provisioning_API\\Controller\\PreferencesController' => __DIR__ . '/..' . '/../lib/Controller/PreferencesController.php',
'OCA\\Provisioning_API\\Controller\\UsersController' => __DIR__ . '/..' . '/../lib/Controller/UsersController.php',
+ 'OCA\\Provisioning_API\\Controller\\VerificationController' => __DIR__ . '/..' . '/../lib/Controller/VerificationController.php',
+ 'OCA\\Provisioning_API\\FederatedShareProviderFactory' => __DIR__ . '/..' . '/../lib/FederatedShareProviderFactory.php',
+ 'OCA\\Provisioning_API\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php',
'OCA\\Provisioning_API\\Middleware\\Exceptions\\NotSubAdminException' => __DIR__ . '/..' . '/../lib/Middleware/Exceptions/NotSubAdminException.php',
'OCA\\Provisioning_API\\Middleware\\ProvisioningApiMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/ProvisioningApiMiddleware.php',
+ 'OCA\\Provisioning_API\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
);
public static function getInitializer(ClassLoader $loader)
diff --git a/apps/provisioning_api/composer/composer/installed.json b/apps/provisioning_api/composer/composer/installed.json
new file mode 100644
index 00000000000..f20a6c47c6d
--- /dev/null
+++ b/apps/provisioning_api/composer/composer/installed.json
@@ -0,0 +1,5 @@
+{
+ "packages": [],
+ "dev": false,
+ "dev-package-names": []
+}
diff --git a/apps/provisioning_api/composer/composer/installed.php b/apps/provisioning_api/composer/composer/installed.php
new file mode 100644
index 00000000000..1a66c7f2416
--- /dev/null
+++ b/apps/provisioning_api/composer/composer/installed.php
@@ -0,0 +1,23 @@
+<?php return array(
+ 'root' => array(
+ 'name' => '__root__',
+ 'pretty_version' => 'dev-master',
+ 'version' => 'dev-master',
+ 'reference' => 'b1797842784b250fb01ed5e3bf130705eb94751b',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../',
+ 'aliases' => array(),
+ 'dev' => false,
+ ),
+ 'versions' => array(
+ '__root__' => array(
+ 'pretty_version' => 'dev-master',
+ 'version' => 'dev-master',
+ 'reference' => 'b1797842784b250fb01ed5e3bf130705eb94751b',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ ),
+);
diff --git a/apps/provisioning_api/img/app.svg b/apps/provisioning_api/img/app.svg
index 7ef7f086921..01b478213d1 100644
--- a/apps/provisioning_api/img/app.svg
+++ b/apps/provisioning_api/img/app.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1" viewBox="0 0 32 32"><path d="M13.733 0a.915.915 0 0 0-.933.934V3.6c-1.182.304-2.243.794-3.267 1.4L7.6 3.068a.93.93 0 0 0-1.334 0l-3.2 3.2a.93.93 0 0 0 0 1.334L5 9.535c-.607 1.024-1.097 2.085-1.4 3.267H.933a.915.915 0 0 0-.933.934v4.533c0 .53.403.934.933.934H3.6c.303 1.182.793 2.243 1.4 3.267l-1.934 1.935a.93.93 0 0 0 0 1.333l3.2 3.2a.93.93 0 0 0 1.333 0L9.532 27c1.024.61 2.085 1.097 3.266 1.4v2.667c0 .53.402.933.932.933h4.534c.53 0 .933-.403.933-.935V28.4c1.18-.305 2.24-.795 3.265-1.4L24.4 28.93a.93.93 0 0 0 1.332 0l3.2-3.2a.93.93 0 0 0 0-1.333L27 22.465c.607-1.024 1.096-2.085 1.4-3.266h2.665a.915.915 0 0 0 .935-.933v-4.534a.915.915 0 0 0-.934-.933H28.4c-.304-1.182-.792-2.243-1.4-3.267L28.932 7.6a.93.93 0 0 0 0-1.334l-3.2-3.2a.93.93 0 0 0-1.333 0L22.465 5c-1.024-.607-2.084-1.097-3.266-1.4V.933A.915.915 0 0 0 18.267 0zM16 8.87A7.134 7.134 0 0 1 23.13 16 7.134 7.134 0 0 1 16 23.133c-3.936 0-7.13-3.196-7.13-7.132S12.063 8.87 16 8.87z" display="block" fill="#fff"/></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#fff"><path d="m236-484-14-61q-11-4-21.5-9.5T180-568l-59 20-42-72 51-40q-2-11-2-22t2-22l-50-40 42-72 59 20q10-8 20-14t22-9l14-61h77l14 61q12 3 22 9t20 14l59-20 42 72-51 40q2 11 2 22t-2 22l50 40-42 72-59-19q-10 8-20.5 13t-21.5 9l-14 61h-77Zm39-122q32 0 54-22t22-54q0-32-22-54t-54-22q-32 0-54 22t-22 54q0 32 22 54t54 22ZM581-40l-17-81q-15-6-29-13.5T508-153l-84 25-60-103 67-58q-2-16-2-31t2-31l-67-58 60-103 84 24q13-10 27-17.5t29-13.5l17-81h120l17 81q15 6 29 13.5t27 17.5l84-24 60 103-67 58q2 16 2 31t-2 31l67 58-60 103-84-25q-13 11-27 18.5T718-121l-17 81H581Zm60-166q48 0 81-33t33-81q0-48-33-81t-81-33q-48 0-81 33t-33 81q0 48 33 81t81 33Z"/></svg> \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/.gitkeep b/apps/provisioning_api/l10n/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/apps/provisioning_api/l10n/.gitkeep
diff --git a/apps/provisioning_api/l10n/ar.js b/apps/provisioning_api/l10n/ar.js
new file mode 100644
index 00000000000..022d8695938
--- /dev/null
+++ b/apps/provisioning_api/l10n/ar.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "يجب أن يكون الحساب الداخل مسؤول نظام أو لديه الصلاحية لتعديل هذا الإعداد.",
+ "Could not create non-existing user ID" : "يتعذّر إنشاء مُعرِّف ID لمستخدِم غير موجود",
+ "User already exists" : "أنت موجودٌ مُسبقاً",
+ "Group %1$s does not exist" : "المجموعة %1$s غير موجودة",
+ "Insufficient privileges for group %1$s" : "أذونات غير كافية للمجموعة %1$s",
+ "No group specified (required for sub-admins)" : "لم يتم تحديد أي مجموعة (مطلوبة للمديرين الفرعيين)",
+ "Sub-admin group does not exist" : "مجموعة المديرين الفرعيين غير موجودة",
+ "Cannot create sub-admins for admin group" : "تعذّر إنشاء مديرين فرعيين لمجموعة المديرين",
+ "No permissions to promote sub-admins" : "أذونات غير كافية لترقية المديرين الفرعيين",
+ "Invalid password value" : "قيمة غير صحيحة لكلمة المرور",
+ "An email address is required, to send a password link to the user." : "عنوان الإيميل مطلوب لإرسال رابط كلمة المرور للمستخدِم",
+ "Required email address was not provided" : "عنوان الإيميل المطلوب لم يتم توفيره",
+ "Invalid quota value: %1$s" : "قيمة غير صحيحة للحصة: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "قيمة غير صحيحة للحصة. %1$s تزيد عن الحد الأقصى للحصة",
+ "Unlimited quota is forbidden on this instance" : "الحصة غير المحدودة غير مسموح بها على هذا الخادوم",
+ "Setting the password is not supported by the users backend" : "تعيين كلمة المرور غير مدعوم من قِبَل الواجهة الخلفية للمستخدمين.",
+ "Invalid language" : "لغة غير صالحة",
+ "Invalid locale" : "اختيار الدولة أو المنطقة غير صحيح",
+ "Invalid first day of week" : "اليوم الأول من الأسبوع غير صحيح",
+ "Cannot remove yourself from the admin group" : "لا يمكنك إزالة نفسك من قائمة المديرين",
+ "Cannot remove yourself from this group as you are a sub-admin" : "لا يمكنك إزالة نفسك من هذه المجموعة باعتبارك مدير فرعي فيها",
+ "Not viable to remove user from the last group you are sub-admin of" : "لا يمكن إزالة المستخدم من آخر مجموعة أنت مدير فرعي لها",
+ "User does not exist" : "المستخدِم غير موجود",
+ "Group does not exist" : "المجموعة غير موجودة",
+ "User is not a sub-admin of this group" : "المستخدِم ليس مدير فرعي على هذه المجموعة",
+ "Email address not available" : "عنوان الإيميل غير متاح",
+ "Sending email failed" : "تعذّر إرسال الإيميل",
+ "Email confirmation" : "تأكيد الإيميل",
+ "To enable the email address %s please click the button below." : "لتمكين عنوان الإيميل %s، إضغط الزر أدناه رجاءً.",
+ "Confirm" : "تأكيد",
+ "Email was already removed from account and cannot be confirmed anymore." : " البريد الإلكتروني سبق حذفه من الحساب و لا يمكن تأكيده بعد الآن.",
+ "Could not verify mail because the token is expired." : "لا يمكن التحقّق من الإيميل بسبب انتهاء صلاحية الأَمارة token.",
+ "Could not verify mail because the token is invalid." : "لا يمكن التحقّق من الإيميل بسبب أن الأَمارة token غير صحيحة.",
+ "An unexpected error occurred. Please contact your admin." : "حدث خطأ غير متوقع. اتصل بالمدير رجاءً.",
+ "Email confirmation successful" : "تمّ توكيد الإيميل بنجاح",
+ "Provisioning API" : "توفير واجهة برمجة التطبيقات API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "يتيح هذا التطبيق مجموعة من واجهات برمجة التطبيقات التي يمكن للأنظمة الخارجية استخدامها لإدارة الحسابات والمجموعات والتطبيقات.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "يتيح هذا التطبيق مجموعة من واجهات برمجة التطبيقات التي يمكن للأنظمة الخارجية استخدامها لإنشاء الحساب وتحريره وحذفه والاستعلام عنه\n\t\tالخصائص، و الاستعلامات، و تعيين المجموعات و إزالتها، و تعيين الحصص، و الاستعلام عن إجمالي مساحة التخزين المستخدمة في نكست كلاود. حسابات مشرف المجموعة \n\t\t يمكنه أيضًا الاستعلام عن نكست كلاود و تنفيذ نفس الوظائف كمشرف للمجموعات التي يديرونها. تتيح واجهة برمجة التطبيقات API أيضاً \n\t\tمشرف للاستعلام عن تطبيقات نكست كلاود النشطة، و معلومات التطبيق، و تمكين التطبيق أو تعطيله عن بُعد. \n\t\tبمجرد تمكين التطبيق، يمكن استخدام طلبات HTTP عبر رأس المصادقة الأساسية لتنفيذ أي من الوظائف \n\t\t المذكورة أعلاه. \nللمزيد من المعلومات، أنظُر توثيق Provisioning API، بما في ذلك أمثلة على الاستدعاءات \n\t\t واستجابات الخادوم."
+},
+"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
diff --git a/apps/provisioning_api/l10n/ar.json b/apps/provisioning_api/l10n/ar.json
new file mode 100644
index 00000000000..4bb2da2a2ff
--- /dev/null
+++ b/apps/provisioning_api/l10n/ar.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "يجب أن يكون الحساب الداخل مسؤول نظام أو لديه الصلاحية لتعديل هذا الإعداد.",
+ "Could not create non-existing user ID" : "يتعذّر إنشاء مُعرِّف ID لمستخدِم غير موجود",
+ "User already exists" : "أنت موجودٌ مُسبقاً",
+ "Group %1$s does not exist" : "المجموعة %1$s غير موجودة",
+ "Insufficient privileges for group %1$s" : "أذونات غير كافية للمجموعة %1$s",
+ "No group specified (required for sub-admins)" : "لم يتم تحديد أي مجموعة (مطلوبة للمديرين الفرعيين)",
+ "Sub-admin group does not exist" : "مجموعة المديرين الفرعيين غير موجودة",
+ "Cannot create sub-admins for admin group" : "تعذّر إنشاء مديرين فرعيين لمجموعة المديرين",
+ "No permissions to promote sub-admins" : "أذونات غير كافية لترقية المديرين الفرعيين",
+ "Invalid password value" : "قيمة غير صحيحة لكلمة المرور",
+ "An email address is required, to send a password link to the user." : "عنوان الإيميل مطلوب لإرسال رابط كلمة المرور للمستخدِم",
+ "Required email address was not provided" : "عنوان الإيميل المطلوب لم يتم توفيره",
+ "Invalid quota value: %1$s" : "قيمة غير صحيحة للحصة: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "قيمة غير صحيحة للحصة. %1$s تزيد عن الحد الأقصى للحصة",
+ "Unlimited quota is forbidden on this instance" : "الحصة غير المحدودة غير مسموح بها على هذا الخادوم",
+ "Setting the password is not supported by the users backend" : "تعيين كلمة المرور غير مدعوم من قِبَل الواجهة الخلفية للمستخدمين.",
+ "Invalid language" : "لغة غير صالحة",
+ "Invalid locale" : "اختيار الدولة أو المنطقة غير صحيح",
+ "Invalid first day of week" : "اليوم الأول من الأسبوع غير صحيح",
+ "Cannot remove yourself from the admin group" : "لا يمكنك إزالة نفسك من قائمة المديرين",
+ "Cannot remove yourself from this group as you are a sub-admin" : "لا يمكنك إزالة نفسك من هذه المجموعة باعتبارك مدير فرعي فيها",
+ "Not viable to remove user from the last group you are sub-admin of" : "لا يمكن إزالة المستخدم من آخر مجموعة أنت مدير فرعي لها",
+ "User does not exist" : "المستخدِم غير موجود",
+ "Group does not exist" : "المجموعة غير موجودة",
+ "User is not a sub-admin of this group" : "المستخدِم ليس مدير فرعي على هذه المجموعة",
+ "Email address not available" : "عنوان الإيميل غير متاح",
+ "Sending email failed" : "تعذّر إرسال الإيميل",
+ "Email confirmation" : "تأكيد الإيميل",
+ "To enable the email address %s please click the button below." : "لتمكين عنوان الإيميل %s، إضغط الزر أدناه رجاءً.",
+ "Confirm" : "تأكيد",
+ "Email was already removed from account and cannot be confirmed anymore." : " البريد الإلكتروني سبق حذفه من الحساب و لا يمكن تأكيده بعد الآن.",
+ "Could not verify mail because the token is expired." : "لا يمكن التحقّق من الإيميل بسبب انتهاء صلاحية الأَمارة token.",
+ "Could not verify mail because the token is invalid." : "لا يمكن التحقّق من الإيميل بسبب أن الأَمارة token غير صحيحة.",
+ "An unexpected error occurred. Please contact your admin." : "حدث خطأ غير متوقع. اتصل بالمدير رجاءً.",
+ "Email confirmation successful" : "تمّ توكيد الإيميل بنجاح",
+ "Provisioning API" : "توفير واجهة برمجة التطبيقات API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "يتيح هذا التطبيق مجموعة من واجهات برمجة التطبيقات التي يمكن للأنظمة الخارجية استخدامها لإدارة الحسابات والمجموعات والتطبيقات.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "يتيح هذا التطبيق مجموعة من واجهات برمجة التطبيقات التي يمكن للأنظمة الخارجية استخدامها لإنشاء الحساب وتحريره وحذفه والاستعلام عنه\n\t\tالخصائص، و الاستعلامات، و تعيين المجموعات و إزالتها، و تعيين الحصص، و الاستعلام عن إجمالي مساحة التخزين المستخدمة في نكست كلاود. حسابات مشرف المجموعة \n\t\t يمكنه أيضًا الاستعلام عن نكست كلاود و تنفيذ نفس الوظائف كمشرف للمجموعات التي يديرونها. تتيح واجهة برمجة التطبيقات API أيضاً \n\t\tمشرف للاستعلام عن تطبيقات نكست كلاود النشطة، و معلومات التطبيق، و تمكين التطبيق أو تعطيله عن بُعد. \n\t\tبمجرد تمكين التطبيق، يمكن استخدام طلبات HTTP عبر رأس المصادقة الأساسية لتنفيذ أي من الوظائف \n\t\t المذكورة أعلاه. \nللمزيد من المعلومات، أنظُر توثيق Provisioning API، بما في ذلك أمثلة على الاستدعاءات \n\t\t واستجابات الخادوم."
+},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/ast.js b/apps/provisioning_api/l10n/ast.js
new file mode 100644
index 00000000000..d7d3bfb88bb
--- /dev/null
+++ b/apps/provisioning_api/l10n/ast.js
@@ -0,0 +1,40 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "La cuenta qu'anició la sesión ha ser de l'alministración o tener l'autorización pa editar esta opción.",
+ "Could not create non-existing user ID" : "Nun se pudo crear la ID d'usuariu inexistente",
+ "User already exists" : "L'usuariu yá esiste",
+ "Group %1$s does not exist" : "El grupu «%1$s» nun esiste",
+ "Insufficient privileges for group %1$s" : "El grupu «%1$s» nun tien los permisos abondos",
+ "No group specified (required for sub-admins)" : "Nun s'especificó nengún grupu (ríquese pa los soalministradores)",
+ "Sub-admin group does not exist" : "El grupu soalministrador nun esiste",
+ "Cannot create sub-admins for admin group" : "Nun se puen crear soalministradores pal grupu d'alministradores",
+ "No permissions to promote sub-admins" : "Nun hai nengún permisu p'ascender a soalministradores",
+ "Invalid password value" : "El valor de la contraseña ye inválidu",
+ "Required email address was not provided" : "Nun se fornió la direición de corréu electrónicu riquida",
+ "Invalid quota value: %1$s" : "El valor de la cuota ye inválidu: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "El valor de la cuota ye inválidu. %1$s supera la cuota máxima.",
+ "Unlimited quota is forbidden on this instance" : "Prohíbese la cuota infinita nesta instancia",
+ "Setting the password is not supported by the users backend" : "El backend d'usuarios nun ye compatible cola configuración de la contraseña",
+ "Invalid language" : "La llingua ye inválida",
+ "Invalid locale" : "La locale ye inválida",
+ "Cannot remove yourself from the admin group" : "Nun pues quitate del grupu d'alministradores",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Nun pues quitate d'esti grupu darréu que yes un soalministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "Nun ye viable quitar l'usuariu del últimu grupu del que yes soalministrador",
+ "User does not exist" : "L'usuariu nun esiste",
+ "Group does not exist" : "El grupu nun esiste",
+ "User is not a sub-admin of this group" : "L'usuariu nun ye un soalministrador d'esti grupu",
+ "Email address not available" : "La direición de corréu electrónicu nun ta disponible",
+ "Sending email failed" : "Falló l'unviu del corréu electrónicu",
+ "Email confirmation" : "Confirmación del corréu electrónicu",
+ "To enable the email address %s please click the button below." : "P'activar la direición de corréu electrónicu «%s», calca nel botón d'abaxo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "Quitóse la direición de corréu electrónicu de la cuenta y yá nun se pue confirmar.",
+ "Could not verify mail because the token is expired." : "Nun se pudo verificar la direición de corréu electrónicu porque'l pase caducó.",
+ "Could not verify mail because the token is invalid." : "Nun se pudo verificar la direición de corréu electrónicu porque'l pase ye inválidu.",
+ "An unexpected error occurred. Please contact your admin." : "Prodúxose un error inesperáu. Ponte en contautu cola alministración.",
+ "Email confirmation successful" : "El mensaxe de cofirmación foi correutu",
+ "Provisioning API" : "API d'aprovisionamientu",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación activa un conxuntu d'APIs que los sistemes esternos puen usar pa xestionar cuentes grupos y aplicaciones."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/ast.json b/apps/provisioning_api/l10n/ast.json
new file mode 100644
index 00000000000..3369728f28c
--- /dev/null
+++ b/apps/provisioning_api/l10n/ast.json
@@ -0,0 +1,38 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "La cuenta qu'anició la sesión ha ser de l'alministración o tener l'autorización pa editar esta opción.",
+ "Could not create non-existing user ID" : "Nun se pudo crear la ID d'usuariu inexistente",
+ "User already exists" : "L'usuariu yá esiste",
+ "Group %1$s does not exist" : "El grupu «%1$s» nun esiste",
+ "Insufficient privileges for group %1$s" : "El grupu «%1$s» nun tien los permisos abondos",
+ "No group specified (required for sub-admins)" : "Nun s'especificó nengún grupu (ríquese pa los soalministradores)",
+ "Sub-admin group does not exist" : "El grupu soalministrador nun esiste",
+ "Cannot create sub-admins for admin group" : "Nun se puen crear soalministradores pal grupu d'alministradores",
+ "No permissions to promote sub-admins" : "Nun hai nengún permisu p'ascender a soalministradores",
+ "Invalid password value" : "El valor de la contraseña ye inválidu",
+ "Required email address was not provided" : "Nun se fornió la direición de corréu electrónicu riquida",
+ "Invalid quota value: %1$s" : "El valor de la cuota ye inválidu: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "El valor de la cuota ye inválidu. %1$s supera la cuota máxima.",
+ "Unlimited quota is forbidden on this instance" : "Prohíbese la cuota infinita nesta instancia",
+ "Setting the password is not supported by the users backend" : "El backend d'usuarios nun ye compatible cola configuración de la contraseña",
+ "Invalid language" : "La llingua ye inválida",
+ "Invalid locale" : "La locale ye inválida",
+ "Cannot remove yourself from the admin group" : "Nun pues quitate del grupu d'alministradores",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Nun pues quitate d'esti grupu darréu que yes un soalministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "Nun ye viable quitar l'usuariu del últimu grupu del que yes soalministrador",
+ "User does not exist" : "L'usuariu nun esiste",
+ "Group does not exist" : "El grupu nun esiste",
+ "User is not a sub-admin of this group" : "L'usuariu nun ye un soalministrador d'esti grupu",
+ "Email address not available" : "La direición de corréu electrónicu nun ta disponible",
+ "Sending email failed" : "Falló l'unviu del corréu electrónicu",
+ "Email confirmation" : "Confirmación del corréu electrónicu",
+ "To enable the email address %s please click the button below." : "P'activar la direición de corréu electrónicu «%s», calca nel botón d'abaxo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "Quitóse la direición de corréu electrónicu de la cuenta y yá nun se pue confirmar.",
+ "Could not verify mail because the token is expired." : "Nun se pudo verificar la direición de corréu electrónicu porque'l pase caducó.",
+ "Could not verify mail because the token is invalid." : "Nun se pudo verificar la direición de corréu electrónicu porque'l pase ye inválidu.",
+ "An unexpected error occurred. Please contact your admin." : "Prodúxose un error inesperáu. Ponte en contautu cola alministración.",
+ "Email confirmation successful" : "El mensaxe de cofirmación foi correutu",
+ "Provisioning API" : "API d'aprovisionamientu",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación activa un conxuntu d'APIs que los sistemes esternos puen usar pa xestionar cuentes grupos y aplicaciones."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/ca.js b/apps/provisioning_api/l10n/ca.js
new file mode 100644
index 00000000000..dd83b291c48
--- /dev/null
+++ b/apps/provisioning_api/l10n/ca.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "El compte que ha iniciat la sessió ha de ser administrador o tenir autorització per a editar aquest paràmetre.",
+ "Could not create non-existing user ID" : "No s'ha pogut crear l'ID d'usuari inexistent",
+ "User already exists" : "L'usuari ja existeix",
+ "Group %1$s does not exist" : "El grup %1$s no existeix",
+ "Insufficient privileges for group %1$s" : "El grup %1$s té privilegis insuficients",
+ "No group specified (required for sub-admins)" : "No s'ha especificat cap grup (obligatori per als subadministradors)",
+ "Sub-admin group does not exist" : "El grup de subadministradors no existeix",
+ "Cannot create sub-admins for admin group" : "No es poden crear subadministradors per al grup d'administració",
+ "No permissions to promote sub-admins" : "No teniu permís per a ascendir subadministradors",
+ "Invalid password value" : "El valor de la contrasenya no és vàlid",
+ "An email address is required, to send a password link to the user." : "Es requereix una adreça de correu electrònic per enviar un enllaç de contrasenya a l'usuari.",
+ "Required email address was not provided" : "No s'ha proporcionat l'adreça electrònica obligatòria",
+ "Invalid quota value: %1$s" : "El valor de quota no és vàlid: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "El valor de quota no és vàlid. %1$s supera la quota màxima",
+ "Unlimited quota is forbidden on this instance" : "Aquesta instància prohibeix definir una quota sense límits",
+ "Setting the password is not supported by the users backend" : "El rerefons d'usuaris no permet definir la contrasenya",
+ "Invalid language" : "La llengua no és vàlida",
+ "Invalid locale" : "La configuració regional no és vàlida",
+ "Invalid first day of week" : "El primer dia de la setmana no és vàlid",
+ "Cannot remove yourself from the admin group" : "No us podeu suprimir del grup d'administració",
+ "Cannot remove yourself from this group as you are a sub-admin" : "No us podeu suprimir d'aquest grup perquè en sou subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "No és viable suprimir l'usuari del darrer grup del qual sou subadministrador",
+ "User does not exist" : "L'usuari no existeix",
+ "Group does not exist" : "El grup no existeix",
+ "User is not a sub-admin of this group" : "L'usuari no és un subadministrador d'aquest grup",
+ "Email address not available" : "L'adreça electrònica no està disponible",
+ "Sending email failed" : "No s'ha pogut enviar el correu electrònic",
+ "Email confirmation" : "Confirmació de l'adreça electrònica",
+ "To enable the email address %s please click the button below." : "Per a habilitar l'adreça electrònica %s, feu clic en el botó següent.",
+ "Confirm" : "Confirma",
+ "Email was already removed from account and cannot be confirmed anymore." : "L'adreça electrònica ja s'ha suprimit del compte i ja no es pot confirmar.",
+ "Could not verify mail because the token is expired." : "No s'ha pogut verificar l'adreça electrònica perquè el testimoni ha caducat.",
+ "Could not verify mail because the token is invalid." : "No s'ha pogut verificar l'adreça electrònica perquè el testimoni no és vàlid.",
+ "An unexpected error occurred. Please contact your admin." : "S'ha produït un error inesperat. Contacteu amb l'administrador.",
+ "Email confirmation successful" : "S'ha confirmat l'adreça electrònica",
+ "Provisioning API" : "API d'aprovisionament",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Aquesta aplicació habilita un conjunt d'API que els sistemes externs poden utilitzar per a administrar comptes, grups i aplicacions.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Aquesta aplicació habilita un conjunt d'API que els sistemes externs poden utilitzar per a crear, editar, suprimir i consultar atributs\n\t\tde compte, consultar, definir i suprimir grups, definir la quota i consultar l'emmagatzematge total en ús al Nextcloud. Els comptes administradors de grup\n\t\ttambé poden enviar consultes al Nextcloud i realitzar les mateixes funcions que un administrador per als grups que administren. L'API també permet a\n\t\tun administrador consultar les aplicacions actives del Nextcloud, la informació de l'aplicació i habilitar o inhabilitar una aplicació de forma remota.\n\t\tUn cop habilitada l'aplicació, es poden utilitzar sol·licituds HTTP mitjançant una capçalera d'autenticació bàsica per a realitzar qualsevol de les funcions\n\t\tindicades anteriorment. Podeu trobar més informació en la documentació de l'API d'aprovisionament, incloent-hi exemples\n\t\tde trucades i respostes del servidor."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/ca.json b/apps/provisioning_api/l10n/ca.json
new file mode 100644
index 00000000000..6d39192d835
--- /dev/null
+++ b/apps/provisioning_api/l10n/ca.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "El compte que ha iniciat la sessió ha de ser administrador o tenir autorització per a editar aquest paràmetre.",
+ "Could not create non-existing user ID" : "No s'ha pogut crear l'ID d'usuari inexistent",
+ "User already exists" : "L'usuari ja existeix",
+ "Group %1$s does not exist" : "El grup %1$s no existeix",
+ "Insufficient privileges for group %1$s" : "El grup %1$s té privilegis insuficients",
+ "No group specified (required for sub-admins)" : "No s'ha especificat cap grup (obligatori per als subadministradors)",
+ "Sub-admin group does not exist" : "El grup de subadministradors no existeix",
+ "Cannot create sub-admins for admin group" : "No es poden crear subadministradors per al grup d'administració",
+ "No permissions to promote sub-admins" : "No teniu permís per a ascendir subadministradors",
+ "Invalid password value" : "El valor de la contrasenya no és vàlid",
+ "An email address is required, to send a password link to the user." : "Es requereix una adreça de correu electrònic per enviar un enllaç de contrasenya a l'usuari.",
+ "Required email address was not provided" : "No s'ha proporcionat l'adreça electrònica obligatòria",
+ "Invalid quota value: %1$s" : "El valor de quota no és vàlid: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "El valor de quota no és vàlid. %1$s supera la quota màxima",
+ "Unlimited quota is forbidden on this instance" : "Aquesta instància prohibeix definir una quota sense límits",
+ "Setting the password is not supported by the users backend" : "El rerefons d'usuaris no permet definir la contrasenya",
+ "Invalid language" : "La llengua no és vàlida",
+ "Invalid locale" : "La configuració regional no és vàlida",
+ "Invalid first day of week" : "El primer dia de la setmana no és vàlid",
+ "Cannot remove yourself from the admin group" : "No us podeu suprimir del grup d'administració",
+ "Cannot remove yourself from this group as you are a sub-admin" : "No us podeu suprimir d'aquest grup perquè en sou subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "No és viable suprimir l'usuari del darrer grup del qual sou subadministrador",
+ "User does not exist" : "L'usuari no existeix",
+ "Group does not exist" : "El grup no existeix",
+ "User is not a sub-admin of this group" : "L'usuari no és un subadministrador d'aquest grup",
+ "Email address not available" : "L'adreça electrònica no està disponible",
+ "Sending email failed" : "No s'ha pogut enviar el correu electrònic",
+ "Email confirmation" : "Confirmació de l'adreça electrònica",
+ "To enable the email address %s please click the button below." : "Per a habilitar l'adreça electrònica %s, feu clic en el botó següent.",
+ "Confirm" : "Confirma",
+ "Email was already removed from account and cannot be confirmed anymore." : "L'adreça electrònica ja s'ha suprimit del compte i ja no es pot confirmar.",
+ "Could not verify mail because the token is expired." : "No s'ha pogut verificar l'adreça electrònica perquè el testimoni ha caducat.",
+ "Could not verify mail because the token is invalid." : "No s'ha pogut verificar l'adreça electrònica perquè el testimoni no és vàlid.",
+ "An unexpected error occurred. Please contact your admin." : "S'ha produït un error inesperat. Contacteu amb l'administrador.",
+ "Email confirmation successful" : "S'ha confirmat l'adreça electrònica",
+ "Provisioning API" : "API d'aprovisionament",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Aquesta aplicació habilita un conjunt d'API que els sistemes externs poden utilitzar per a administrar comptes, grups i aplicacions.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Aquesta aplicació habilita un conjunt d'API que els sistemes externs poden utilitzar per a crear, editar, suprimir i consultar atributs\n\t\tde compte, consultar, definir i suprimir grups, definir la quota i consultar l'emmagatzematge total en ús al Nextcloud. Els comptes administradors de grup\n\t\ttambé poden enviar consultes al Nextcloud i realitzar les mateixes funcions que un administrador per als grups que administren. L'API també permet a\n\t\tun administrador consultar les aplicacions actives del Nextcloud, la informació de l'aplicació i habilitar o inhabilitar una aplicació de forma remota.\n\t\tUn cop habilitada l'aplicació, es poden utilitzar sol·licituds HTTP mitjançant una capçalera d'autenticació bàsica per a realitzar qualsevol de les funcions\n\t\tindicades anteriorment. Podeu trobar més informació en la documentació de l'API d'aprovisionament, incloent-hi exemples\n\t\tde trucades i respostes del servidor."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/cs.js b/apps/provisioning_api/l10n/cs.js
new file mode 100644
index 00000000000..a6fdb3482fa
--- /dev/null
+++ b/apps/provisioning_api/l10n/cs.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Aby mohl upravovat toto nastavení, je třeba, aby přihlášený účet byl správcem nebo měl potřebná pověření.",
+ "Could not create non-existing user ID" : "Není možné vytvořit neexistující identifikátor uživatele",
+ "User already exists" : "Uživatel už existuje",
+ "Group %1$s does not exist" : "Skupina %1$s neexistuje",
+ "Insufficient privileges for group %1$s" : "Nedostatečná oprávnění pro skupinu %1$s",
+ "No group specified (required for sub-admins)" : "Neurčena žádná skupina (vyžadováno pro dílčí správce)",
+ "Sub-admin group does not exist" : "Skupina dílčích správců neexistuje",
+ "Cannot create sub-admins for admin group" : "Nepodařilo se vytvořit dílčí správce pro skupinu správců",
+ "No permissions to promote sub-admins" : "Chybí oprávnění povyšovat dílčí správce",
+ "Invalid password value" : "Neplatná hodnota hesla",
+ "An email address is required, to send a password link to the user." : "Je vyžadována e-mailová adresa (pro zaslání odkazu na heslo uživateli).",
+ "Required email address was not provided" : "Nebyla poskytnuta potřebná e-mailová adresa",
+ "User creation failed" : "Vytváření uživatele se nezdařilo",
+ "Invalid quota value: %1$s" : "Neplatná hodnota kvóty: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Neplatná hodnota kvóty. %1$s překračuje maximální kvótu",
+ "Unlimited quota is forbidden on this instance" : "Neomezená kvóta není na této instanci dovolena",
+ "Setting the password is not supported by the users backend" : "Nastavování hesla není touto podpůrnou vrstvou pro uživatelské účty podporována",
+ "Invalid language" : "Neplatný jazyk",
+ "Invalid locale" : "Neplatná místní a jazyková nastavení",
+ "Invalid first day of week" : "Neplatný první den v týdnu",
+ "Cannot remove yourself from the admin group" : "Není možné odebrat sama sebe ze skupiny správců",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Není možné odebrat sama sebe z této skupiny protože jste dílčím správcem",
+ "Not viable to remove user from the last group you are sub-admin of" : "Není uskutečnitelné odebrat uživatele z poslední skupiny, které jste dílčím správcem",
+ "User does not exist" : "Uživatel neexistuje",
+ "Group does not exist" : "Skupina neexistuje",
+ "User is not a sub-admin of this group" : "Uživatel není dílčím správcem této skupiny",
+ "Email address not available" : "E-mailová adresa není k dispozici",
+ "Sending email failed" : "Odeslání e-mailu se nezdařilo",
+ "Email confirmation" : "Potvrzení e-mailu",
+ "To enable the email address %s please click the button below." : "Pokud chcete povolit e-mailovou adresu %s, klikněte na tlačítko níže.",
+ "Confirm" : "Potvrdit",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mail už byl odebrán z účtu a není už možné ho potvrdit.",
+ "Could not verify mail because the token is expired." : "E-mail není možné ověřit, protože platnost tokenu skončila.",
+ "Could not verify mail because the token is invalid." : "E-mail není možné ověřit, protože token není platný.",
+ "An unexpected error occurred. Please contact your admin." : "Došlo k neočekávané chybě. Obraťte se na svého správce.",
+ "Email confirmation successful" : "E-mail úspěšně potvrzen",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Tato aplikace zapíná sadu PI rozhraní, kterou mohou využívat externí systémy pro správu účtů, skupin a aplikací.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Tato aplikace umožňuje nastavit aplikační programová rozhraní (API) pro externí systémy, která je možné použít pro vytváření, upravování, mazání a dotazování se na atributy účtů,\n\t\tdotazovat se na, nastavovat a odebírat skupiny, nastavovat kvóty a dotazovat se na celkové využívání úložiště v Nextcloud. Správci skupin\n\t\tse také mohou Nextcloud dotazovat a provádět stejné funkce jako správci pro skupiny, které spravují. API také umožňuje\n\t\tsprávci dotazovat se na aktivní Nextcloud aplikace, informace o nich a zapínat nebo vypínat aplikace na dálku.\n\t\tJakmile je aplikace zapnutá, HTTP požadavky je možné použít prostřednictvím Basic Auth záhlaví pro provádění jakékoli\n\t\tz výše zmíněných funkcí. Více informací je k dispozici v dokumentaci k Provisioning API, včetně ukázek volání\n\t\ta odpovědí ze serveru."
+},
+"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;");
diff --git a/apps/provisioning_api/l10n/cs.json b/apps/provisioning_api/l10n/cs.json
new file mode 100644
index 00000000000..6f9ad347813
--- /dev/null
+++ b/apps/provisioning_api/l10n/cs.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Aby mohl upravovat toto nastavení, je třeba, aby přihlášený účet byl správcem nebo měl potřebná pověření.",
+ "Could not create non-existing user ID" : "Není možné vytvořit neexistující identifikátor uživatele",
+ "User already exists" : "Uživatel už existuje",
+ "Group %1$s does not exist" : "Skupina %1$s neexistuje",
+ "Insufficient privileges for group %1$s" : "Nedostatečná oprávnění pro skupinu %1$s",
+ "No group specified (required for sub-admins)" : "Neurčena žádná skupina (vyžadováno pro dílčí správce)",
+ "Sub-admin group does not exist" : "Skupina dílčích správců neexistuje",
+ "Cannot create sub-admins for admin group" : "Nepodařilo se vytvořit dílčí správce pro skupinu správců",
+ "No permissions to promote sub-admins" : "Chybí oprávnění povyšovat dílčí správce",
+ "Invalid password value" : "Neplatná hodnota hesla",
+ "An email address is required, to send a password link to the user." : "Je vyžadována e-mailová adresa (pro zaslání odkazu na heslo uživateli).",
+ "Required email address was not provided" : "Nebyla poskytnuta potřebná e-mailová adresa",
+ "User creation failed" : "Vytváření uživatele se nezdařilo",
+ "Invalid quota value: %1$s" : "Neplatná hodnota kvóty: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Neplatná hodnota kvóty. %1$s překračuje maximální kvótu",
+ "Unlimited quota is forbidden on this instance" : "Neomezená kvóta není na této instanci dovolena",
+ "Setting the password is not supported by the users backend" : "Nastavování hesla není touto podpůrnou vrstvou pro uživatelské účty podporována",
+ "Invalid language" : "Neplatný jazyk",
+ "Invalid locale" : "Neplatná místní a jazyková nastavení",
+ "Invalid first day of week" : "Neplatný první den v týdnu",
+ "Cannot remove yourself from the admin group" : "Není možné odebrat sama sebe ze skupiny správců",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Není možné odebrat sama sebe z této skupiny protože jste dílčím správcem",
+ "Not viable to remove user from the last group you are sub-admin of" : "Není uskutečnitelné odebrat uživatele z poslední skupiny, které jste dílčím správcem",
+ "User does not exist" : "Uživatel neexistuje",
+ "Group does not exist" : "Skupina neexistuje",
+ "User is not a sub-admin of this group" : "Uživatel není dílčím správcem této skupiny",
+ "Email address not available" : "E-mailová adresa není k dispozici",
+ "Sending email failed" : "Odeslání e-mailu se nezdařilo",
+ "Email confirmation" : "Potvrzení e-mailu",
+ "To enable the email address %s please click the button below." : "Pokud chcete povolit e-mailovou adresu %s, klikněte na tlačítko níže.",
+ "Confirm" : "Potvrdit",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mail už byl odebrán z účtu a není už možné ho potvrdit.",
+ "Could not verify mail because the token is expired." : "E-mail není možné ověřit, protože platnost tokenu skončila.",
+ "Could not verify mail because the token is invalid." : "E-mail není možné ověřit, protože token není platný.",
+ "An unexpected error occurred. Please contact your admin." : "Došlo k neočekávané chybě. Obraťte se na svého správce.",
+ "Email confirmation successful" : "E-mail úspěšně potvrzen",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Tato aplikace zapíná sadu PI rozhraní, kterou mohou využívat externí systémy pro správu účtů, skupin a aplikací.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Tato aplikace umožňuje nastavit aplikační programová rozhraní (API) pro externí systémy, která je možné použít pro vytváření, upravování, mazání a dotazování se na atributy účtů,\n\t\tdotazovat se na, nastavovat a odebírat skupiny, nastavovat kvóty a dotazovat se na celkové využívání úložiště v Nextcloud. Správci skupin\n\t\tse také mohou Nextcloud dotazovat a provádět stejné funkce jako správci pro skupiny, které spravují. API také umožňuje\n\t\tsprávci dotazovat se na aktivní Nextcloud aplikace, informace o nich a zapínat nebo vypínat aplikace na dálku.\n\t\tJakmile je aplikace zapnutá, HTTP požadavky je možné použít prostřednictvím Basic Auth záhlaví pro provádění jakékoli\n\t\tz výše zmíněných funkcí. Více informací je k dispozici v dokumentaci k Provisioning API, včetně ukázek volání\n\t\ta odpovědí ze serveru."
+},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/da.js b/apps/provisioning_api/l10n/da.js
new file mode 100644
index 00000000000..b752d549f6e
--- /dev/null
+++ b/apps/provisioning_api/l10n/da.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Den indloggede konto skal være en administrator eller have autorisation til at redigere denne indstilling.",
+ "Could not create non-existing user ID" : "Kunne ikke oprette en ikke-eksisterende bruger-ID",
+ "User already exists" : "Brugeren eksisterer allerede",
+ "Group %1$s does not exist" : "Gruppen %1$s eksisterer ikke",
+ "Insufficient privileges for group %1$s" : "Utilstrækkelige privilegier for gruppen %1$s",
+ "No group specified (required for sub-admins)" : "Ingen gruppe specificeret (påkrævet for underadministratorer)",
+ "Sub-admin group does not exist" : "Underadministratorgruppen eksisterer ikke",
+ "Cannot create sub-admins for admin group" : "Kan ikke oprette underadministratorer for administratorgruppen",
+ "No permissions to promote sub-admins" : "Ingen tilladelser til at forfremme underadministratorer",
+ "Invalid password value" : "Ugyldig adgangskodeværdi",
+ "An email address is required, to send a password link to the user." : "En e-mailadresse er krævet for at sende et adgangskodelink til brugeren.",
+ "Required email address was not provided" : "Den krævede e-mailadresse blev ikke oplyst",
+ "Invalid quota value: %1$s" : "Ugyldig kvoteværdi: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ugyldig kvoteværdi. %1$s overskrider den maksimale kvote",
+ "Unlimited quota is forbidden on this instance" : "Ubegrænset kvote er forbudt i denne instans",
+ "Setting the password is not supported by the users backend" : "Indstilling af adgangskode understøttes ikke af brugernes backend",
+ "Invalid language" : "Ugyldigt sprog",
+ "Invalid locale" : "Ugyldigt landestandard",
+ "Invalid first day of week" : "Ugyldig første dag i ugen",
+ "Cannot remove yourself from the admin group" : "Du kan ikke fjerne dig selv fra administratorgruppen",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Du kan ikke fjerne dig selv fra denne gruppe, da du er en underadministrator",
+ "Not viable to remove user from the last group you are sub-admin of" : "Ikke muligt at fjerne brugeren fra den sidste gruppe, du er underadministrator for",
+ "User does not exist" : "Brugeren eksisterer ikke",
+ "Group does not exist" : "Gruppen eksisterer ikke",
+ "User is not a sub-admin of this group" : "Brugeren er ikke underadministrator for denne gruppe",
+ "Email address not available" : "E-mailadresse ikke tilgængelig",
+ "Sending email failed" : "Det lykkedes ikke at sende e-mailen",
+ "Email confirmation" : "E-mailbekræftelse",
+ "To enable the email address %s please click the button below." : "For at aktivere e-mailadressen %s, klik venligst på knappen nedenfor.",
+ "Confirm" : "Bekræft",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mailen er allerede fjernet fra kontoen og kan ikke bekræftes længere.",
+ "Could not verify mail because the token is expired." : "Kunne ikke bekræfte e-mail, da token er udløbet.",
+ "Could not verify mail because the token is invalid." : "Kunne ikke bekræfte e-mail, da token er ugyldig.",
+ "An unexpected error occurred. Please contact your admin." : "Der opstod en uventet fejl. Kontakt venligst din administrator.",
+ "Email confirmation successful" : "E-mailbekræftelse lykkedes",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Denne applikation muliggør et sæt af API'er, som eksterne systemer kan bruge til at administrere konti, grupper og apps.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Denne applikation muliggør et sæt af API'er, som eksterne systemer kan bruge til at oprette, redigere, slette og forespørge på kontoattributter, forespørge på, oprette og fjerne grupper, sætte kvoter og forespørge på det totale lagerforbrug i Nextcloud. Gruppeadministrator-konti kan også forespørge på Nextcloud og udføre de samme funktioner som en administrator for de grupper, de administrerer. API'en giver også en administrator mulighed for at forespørge på aktive Nextcloud-applikationer, applikationsinformation og til at aktivere eller deaktivere en app fjernstyret. Når appen er aktiveret, kan HTTP-anmodninger bruges via en Basic Auth header til at udføre nogen af de funktioner, der er nævnt ovenfor. Mere information er tilgængelig i dokumentationen for Provisioning API, inklusive eksempelopkald og serverrespons."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/da.json b/apps/provisioning_api/l10n/da.json
new file mode 100644
index 00000000000..2156565221f
--- /dev/null
+++ b/apps/provisioning_api/l10n/da.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Den indloggede konto skal være en administrator eller have autorisation til at redigere denne indstilling.",
+ "Could not create non-existing user ID" : "Kunne ikke oprette en ikke-eksisterende bruger-ID",
+ "User already exists" : "Brugeren eksisterer allerede",
+ "Group %1$s does not exist" : "Gruppen %1$s eksisterer ikke",
+ "Insufficient privileges for group %1$s" : "Utilstrækkelige privilegier for gruppen %1$s",
+ "No group specified (required for sub-admins)" : "Ingen gruppe specificeret (påkrævet for underadministratorer)",
+ "Sub-admin group does not exist" : "Underadministratorgruppen eksisterer ikke",
+ "Cannot create sub-admins for admin group" : "Kan ikke oprette underadministratorer for administratorgruppen",
+ "No permissions to promote sub-admins" : "Ingen tilladelser til at forfremme underadministratorer",
+ "Invalid password value" : "Ugyldig adgangskodeværdi",
+ "An email address is required, to send a password link to the user." : "En e-mailadresse er krævet for at sende et adgangskodelink til brugeren.",
+ "Required email address was not provided" : "Den krævede e-mailadresse blev ikke oplyst",
+ "Invalid quota value: %1$s" : "Ugyldig kvoteværdi: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ugyldig kvoteværdi. %1$s overskrider den maksimale kvote",
+ "Unlimited quota is forbidden on this instance" : "Ubegrænset kvote er forbudt i denne instans",
+ "Setting the password is not supported by the users backend" : "Indstilling af adgangskode understøttes ikke af brugernes backend",
+ "Invalid language" : "Ugyldigt sprog",
+ "Invalid locale" : "Ugyldigt landestandard",
+ "Invalid first day of week" : "Ugyldig første dag i ugen",
+ "Cannot remove yourself from the admin group" : "Du kan ikke fjerne dig selv fra administratorgruppen",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Du kan ikke fjerne dig selv fra denne gruppe, da du er en underadministrator",
+ "Not viable to remove user from the last group you are sub-admin of" : "Ikke muligt at fjerne brugeren fra den sidste gruppe, du er underadministrator for",
+ "User does not exist" : "Brugeren eksisterer ikke",
+ "Group does not exist" : "Gruppen eksisterer ikke",
+ "User is not a sub-admin of this group" : "Brugeren er ikke underadministrator for denne gruppe",
+ "Email address not available" : "E-mailadresse ikke tilgængelig",
+ "Sending email failed" : "Det lykkedes ikke at sende e-mailen",
+ "Email confirmation" : "E-mailbekræftelse",
+ "To enable the email address %s please click the button below." : "For at aktivere e-mailadressen %s, klik venligst på knappen nedenfor.",
+ "Confirm" : "Bekræft",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mailen er allerede fjernet fra kontoen og kan ikke bekræftes længere.",
+ "Could not verify mail because the token is expired." : "Kunne ikke bekræfte e-mail, da token er udløbet.",
+ "Could not verify mail because the token is invalid." : "Kunne ikke bekræfte e-mail, da token er ugyldig.",
+ "An unexpected error occurred. Please contact your admin." : "Der opstod en uventet fejl. Kontakt venligst din administrator.",
+ "Email confirmation successful" : "E-mailbekræftelse lykkedes",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Denne applikation muliggør et sæt af API'er, som eksterne systemer kan bruge til at administrere konti, grupper og apps.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Denne applikation muliggør et sæt af API'er, som eksterne systemer kan bruge til at oprette, redigere, slette og forespørge på kontoattributter, forespørge på, oprette og fjerne grupper, sætte kvoter og forespørge på det totale lagerforbrug i Nextcloud. Gruppeadministrator-konti kan også forespørge på Nextcloud og udføre de samme funktioner som en administrator for de grupper, de administrerer. API'en giver også en administrator mulighed for at forespørge på aktive Nextcloud-applikationer, applikationsinformation og til at aktivere eller deaktivere en app fjernstyret. Når appen er aktiveret, kan HTTP-anmodninger bruges via en Basic Auth header til at udføre nogen af de funktioner, der er nævnt ovenfor. Mere information er tilgængelig i dokumentationen for Provisioning API, inklusive eksempelopkald og serverrespons."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/de.js b/apps/provisioning_api/l10n/de.js
new file mode 100644
index 00000000000..f4e30f174f7
--- /dev/null
+++ b/apps/provisioning_api/l10n/de.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Das angemeldete Konto muss ein Administrationskonto sein oder die Berechtigung haben, diese Einstellung zu bearbeiten.",
+ "Could not create non-existing user ID" : "Nicht vorhandene Benutzer-ID konnte nicht erstellen werden",
+ "User already exists" : "Benutzer existiert bereits",
+ "Group %1$s does not exist" : "Gruppe %1$s existiert nicht",
+ "Insufficient privileges for group %1$s" : "Unzureichende Berechtigungen für Gruppe %1$s",
+ "No group specified (required for sub-admins)" : "Keine Gruppe angegeben (erforderlich für Unteradministration)",
+ "Sub-admin group does not exist" : "Die Unteradministrations-Gruppe existiert nicht",
+ "Cannot create sub-admins for admin group" : "Kann keine Unteradministration für die Administrations-Gruppe erstellen",
+ "No permissions to promote sub-admins" : "Keine Berechtigungen, um Unteradministration zu ernennen",
+ "Invalid password value" : "Ungültiger Passwort-Wert",
+ "An email address is required, to send a password link to the user." : "Um dem Benutzer einen Passwortlink zu senden, ist eine E-Mail-Adresse erforderlich.",
+ "Required email address was not provided" : "Erforderliche E-Mail-Adresse wurde nicht angegeben",
+ "User creation failed" : "Benutzererstellung fehlgeschlagen",
+ "Invalid quota value: %1$s" : "Ungültiger Wert für Speicherkontigent: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ungültiger Wert für Speicherkontigent. %1$s überschreitet das maximale Kontigent",
+ "Unlimited quota is forbidden on this instance" : "Unbegrenztes Speicherkontigent ist auf dieser Instanz unzulässig",
+ "Setting the password is not supported by the users backend" : "Das Passwort kann nicht über das Benutzerbackend festgelegt werden",
+ "Invalid language" : "Ungültige Sprache",
+ "Invalid locale" : "Ungültige Lokalisierung",
+ "Invalid first day of week" : "Ungültiger erster Tag der Woche",
+ "Cannot remove yourself from the admin group" : "Du kannst dich nicht selbst aus der Administrationsgruppe entfernen.",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Du kannst dich nicht selbst aus dieser Gruppe entfernen, da du zur Unteradministration gehörst.",
+ "Not viable to remove user from the last group you are sub-admin of" : "Das Konto aus der letzten Gruppe zu entfernen, in der du zur Unteradministration gehörst ist nicht möglich.",
+ "User does not exist" : "Konto existiert nicht",
+ "Group does not exist" : "Gruppe existiert nicht",
+ "User is not a sub-admin of this group" : "Konto ist kein Unteradministrator dieser Gruppe",
+ "Email address not available" : "E-Mail-Adresse nicht verfügbar",
+ "Sending email failed" : "Senden der E-Mail ist fehlgeschlagen",
+ "Email confirmation" : "E-Mail-Bestätigung",
+ "To enable the email address %s please click the button below." : "Um die E-Mailadresse %s zu bestätigen, auf die untenstehende Schaltfläche klicken.",
+ "Confirm" : "Bestätigen",
+ "Email was already removed from account and cannot be confirmed anymore." : "Diese E-Mail-Adresse wurde bereits aus dem Konto entfernt und kann nicht mehr bestätigt werden.",
+ "Could not verify mail because the token is expired." : "Die E-Mailadresse konnte nicht verifiziert werden, da das Token abgelaufen ist.",
+ "Could not verify mail because the token is invalid." : "Die E-Mailadresse konnte nicht verifiziert werden, da der Token ungültig ist.",
+ "An unexpected error occurred. Please contact your admin." : "Es ist ein unerwarteter Fehler aufgetreten, bitte kontaktiere deine Administration.",
+ "Email confirmation successful" : "Die E-Mail Bestätigung war erfolgreich.",
+ "Provisioning API" : "Bereitstellungs-API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Diese Applikation stellt einen Satz von APIs für externe Systeme zur Verfügung um Konten, Gruppen und Apps zu verwalten.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Diese Anwendung aktiviert eine Reihe von APIs, mit denen externe Systeme Konten erstellen, bearbeiten, löschen und abfragen können\n\t\tAttribute, Gruppen abfragen, festlegen und entfernen, Kontingent festlegen und Gesamtspeicher abfragen, der in Nextcloud verwendet wird. Gruppenadministrationskonto\n\t\tDu kannst auch Nextcloud abfragen und dieselben Funktionen wie ein Administrator für von dir verwaltete Gruppen ausführen. Die API ermöglicht auch\n\t\tEine Administration, die nach aktiven Nextcloud-Anwendungen und Anwendungsinformationen fragt und eine App entfernt aktiviert oder deaktiviert.\n\t\tSobald die App aktiviert ist, können HTTP-Anforderungen über einen Basic Auth-Header verwendet werden, um eine der Funktionen auszuführen\n\t\toben aufgelistet. Weitere Informationen findest du in der Bereitstellung-API Dokumentation, einschließlich Beispielaufrufen\n\t\tund Serverantworten."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/de.json b/apps/provisioning_api/l10n/de.json
new file mode 100644
index 00000000000..85c24424b21
--- /dev/null
+++ b/apps/provisioning_api/l10n/de.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Das angemeldete Konto muss ein Administrationskonto sein oder die Berechtigung haben, diese Einstellung zu bearbeiten.",
+ "Could not create non-existing user ID" : "Nicht vorhandene Benutzer-ID konnte nicht erstellen werden",
+ "User already exists" : "Benutzer existiert bereits",
+ "Group %1$s does not exist" : "Gruppe %1$s existiert nicht",
+ "Insufficient privileges for group %1$s" : "Unzureichende Berechtigungen für Gruppe %1$s",
+ "No group specified (required for sub-admins)" : "Keine Gruppe angegeben (erforderlich für Unteradministration)",
+ "Sub-admin group does not exist" : "Die Unteradministrations-Gruppe existiert nicht",
+ "Cannot create sub-admins for admin group" : "Kann keine Unteradministration für die Administrations-Gruppe erstellen",
+ "No permissions to promote sub-admins" : "Keine Berechtigungen, um Unteradministration zu ernennen",
+ "Invalid password value" : "Ungültiger Passwort-Wert",
+ "An email address is required, to send a password link to the user." : "Um dem Benutzer einen Passwortlink zu senden, ist eine E-Mail-Adresse erforderlich.",
+ "Required email address was not provided" : "Erforderliche E-Mail-Adresse wurde nicht angegeben",
+ "User creation failed" : "Benutzererstellung fehlgeschlagen",
+ "Invalid quota value: %1$s" : "Ungültiger Wert für Speicherkontigent: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ungültiger Wert für Speicherkontigent. %1$s überschreitet das maximale Kontigent",
+ "Unlimited quota is forbidden on this instance" : "Unbegrenztes Speicherkontigent ist auf dieser Instanz unzulässig",
+ "Setting the password is not supported by the users backend" : "Das Passwort kann nicht über das Benutzerbackend festgelegt werden",
+ "Invalid language" : "Ungültige Sprache",
+ "Invalid locale" : "Ungültige Lokalisierung",
+ "Invalid first day of week" : "Ungültiger erster Tag der Woche",
+ "Cannot remove yourself from the admin group" : "Du kannst dich nicht selbst aus der Administrationsgruppe entfernen.",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Du kannst dich nicht selbst aus dieser Gruppe entfernen, da du zur Unteradministration gehörst.",
+ "Not viable to remove user from the last group you are sub-admin of" : "Das Konto aus der letzten Gruppe zu entfernen, in der du zur Unteradministration gehörst ist nicht möglich.",
+ "User does not exist" : "Konto existiert nicht",
+ "Group does not exist" : "Gruppe existiert nicht",
+ "User is not a sub-admin of this group" : "Konto ist kein Unteradministrator dieser Gruppe",
+ "Email address not available" : "E-Mail-Adresse nicht verfügbar",
+ "Sending email failed" : "Senden der E-Mail ist fehlgeschlagen",
+ "Email confirmation" : "E-Mail-Bestätigung",
+ "To enable the email address %s please click the button below." : "Um die E-Mailadresse %s zu bestätigen, auf die untenstehende Schaltfläche klicken.",
+ "Confirm" : "Bestätigen",
+ "Email was already removed from account and cannot be confirmed anymore." : "Diese E-Mail-Adresse wurde bereits aus dem Konto entfernt und kann nicht mehr bestätigt werden.",
+ "Could not verify mail because the token is expired." : "Die E-Mailadresse konnte nicht verifiziert werden, da das Token abgelaufen ist.",
+ "Could not verify mail because the token is invalid." : "Die E-Mailadresse konnte nicht verifiziert werden, da der Token ungültig ist.",
+ "An unexpected error occurred. Please contact your admin." : "Es ist ein unerwarteter Fehler aufgetreten, bitte kontaktiere deine Administration.",
+ "Email confirmation successful" : "Die E-Mail Bestätigung war erfolgreich.",
+ "Provisioning API" : "Bereitstellungs-API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Diese Applikation stellt einen Satz von APIs für externe Systeme zur Verfügung um Konten, Gruppen und Apps zu verwalten.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Diese Anwendung aktiviert eine Reihe von APIs, mit denen externe Systeme Konten erstellen, bearbeiten, löschen und abfragen können\n\t\tAttribute, Gruppen abfragen, festlegen und entfernen, Kontingent festlegen und Gesamtspeicher abfragen, der in Nextcloud verwendet wird. Gruppenadministrationskonto\n\t\tDu kannst auch Nextcloud abfragen und dieselben Funktionen wie ein Administrator für von dir verwaltete Gruppen ausführen. Die API ermöglicht auch\n\t\tEine Administration, die nach aktiven Nextcloud-Anwendungen und Anwendungsinformationen fragt und eine App entfernt aktiviert oder deaktiviert.\n\t\tSobald die App aktiviert ist, können HTTP-Anforderungen über einen Basic Auth-Header verwendet werden, um eine der Funktionen auszuführen\n\t\toben aufgelistet. Weitere Informationen findest du in der Bereitstellung-API Dokumentation, einschließlich Beispielaufrufen\n\t\tund Serverantworten."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/de_DE.js b/apps/provisioning_api/l10n/de_DE.js
new file mode 100644
index 00000000000..0a44ee87126
--- /dev/null
+++ b/apps/provisioning_api/l10n/de_DE.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Das angemeldete Konto muss ein Administrationskonto sein oder die Berechtigung haben, diese Einstellung zu bearbeiten.",
+ "Could not create non-existing user ID" : "Nicht vorhandene Benutzer-ID konnte nicht erstellen werden",
+ "User already exists" : "Benutzer existiert bereits",
+ "Group %1$s does not exist" : "Gruppe %1$s existiert nicht",
+ "Insufficient privileges for group %1$s" : "Unzureichende Berechtigungen für Gruppe %1$s",
+ "No group specified (required for sub-admins)" : "Keine Gruppe angegeben (erforderlich für Unteradministratoren)",
+ "Sub-admin group does not exist" : "Die Unteradministratoren-Gruppe existiert nicht",
+ "Cannot create sub-admins for admin group" : "Kann keine Unteradministratoren für die Administrationsgruppe erstellen",
+ "No permissions to promote sub-admins" : "Keine Berechtigungen, um Unteradministratoren zu ernennen",
+ "Invalid password value" : "Ungültiger Passwort-Wert",
+ "An email address is required, to send a password link to the user." : "Um dem Benutzer einen Passwortlink zu senden, ist eine E-Mail-Adresse erforderlich.",
+ "Required email address was not provided" : "Erforderliche E-Mail-Adresse wurde nicht angegeben",
+ "User creation failed" : "Benutzererstellung fehlgeschlagen",
+ "Invalid quota value: %1$s" : "Ungültiger Wert für Speicherkontigent: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ungültiger Wert für Speicherkontigent. %1$s überschreitet das maximale Kontigent",
+ "Unlimited quota is forbidden on this instance" : "Unbegrenztes Speicherkontigent ist auf dieser Instanz unzulässig",
+ "Setting the password is not supported by the users backend" : "Das Passwort kann nicht über das Benutzerbackend festgelegt werden",
+ "Invalid language" : "Ungültige Sprache",
+ "Invalid locale" : "Ungültige Lokalisierung",
+ "Invalid first day of week" : "Ungültiger erster Tag der Woche",
+ "Cannot remove yourself from the admin group" : "Sie können sich nicht selbst aus der Administrationsgruppe entfernen",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Sie können sich nicht selbst aus dieser Gruppe entfernen, da Sie ein Unteradministrator sind",
+ "Not viable to remove user from the last group you are sub-admin of" : "Den Benutzer aus der letzten Gruppe zu entfernen, in der Sie Unteradministrator sind ist nicht möglich.",
+ "User does not exist" : "Benutzer existiert nicht",
+ "Group does not exist" : "Gruppe existiert nicht",
+ "User is not a sub-admin of this group" : "Benutzer ist kein Unteradministrator dieser Gruppe",
+ "Email address not available" : "E-Mail-Adresse nicht verfügbar",
+ "Sending email failed" : "Senden der E-Mail ist fehlgeschlagen",
+ "Email confirmation" : "E-Mail-Bestätigung",
+ "To enable the email address %s please click the button below." : "Um die E-Mail-Adresse %s zu bestätigen, klicken Sie bitte auf die untenstehende Schaltfläche.",
+ "Confirm" : "Bestätigen",
+ "Email was already removed from account and cannot be confirmed anymore." : "Diese E-Mail-Adresse wurde bereits aus dem Konto entfernt und kann nicht mehr bestätigt werden.",
+ "Could not verify mail because the token is expired." : "Die E-Mail-Adresse konnte aufgrund eines abgelaufenen Tokens nicht zurückgesetzt werden",
+ "Could not verify mail because the token is invalid." : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht bestätigt werden",
+ "An unexpected error occurred. Please contact your admin." : "Es ist ein unerwarteter Fehler aufgetreten, bitte kontaktieren Sie Ihre Administration.",
+ "Email confirmation successful" : "E-Mail-Adresse wurde bestätgt",
+ "Provisioning API" : "Bereitstellung-API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Diese Applikation stellt einen Satz von APIs für externe Systeme zur Verfügung um Konten, Gruppen und Apps zu verwalten.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Diese Anwendung aktiviert eine Reihe von APIs, mit denen externe Systeme Konten erstellen, bearbeiten, löschen und abfragen können\n\t\tAttribute, Gruppen abfragen, festlegen und entfernen, Kontingent festlegen und Gesamtspeicher abfragen, der in Nextcloud verwendet wird. Gruppenadministrationskonto\n\t\tSie können auch Nextcloud abfragen und dieselben Funktionen wie ein Administrator für von ihnen verwaltete Gruppen ausführen. Die API ermöglicht auch\n\t\tEin Administrator, der nach aktiven Nextcloud-Anwendungen und Anwendungsinformationen fragt und eine App entfernt aktiviert oder deaktiviert.\n\t\tSobald die App aktiviert ist, können HTTP-Anforderungen über einen Basic Auth-Header verwendet werden, um eine der Funktionen auszuführen\n\t\toben aufgelistet. Weitere Informationen finden Sie in der Bereitstellung-API Dokumentation, einschließlich Beispielaufrufen\n\t\tund Serverantworten."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/de_DE.json b/apps/provisioning_api/l10n/de_DE.json
new file mode 100644
index 00000000000..84036ced30b
--- /dev/null
+++ b/apps/provisioning_api/l10n/de_DE.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Das angemeldete Konto muss ein Administrationskonto sein oder die Berechtigung haben, diese Einstellung zu bearbeiten.",
+ "Could not create non-existing user ID" : "Nicht vorhandene Benutzer-ID konnte nicht erstellen werden",
+ "User already exists" : "Benutzer existiert bereits",
+ "Group %1$s does not exist" : "Gruppe %1$s existiert nicht",
+ "Insufficient privileges for group %1$s" : "Unzureichende Berechtigungen für Gruppe %1$s",
+ "No group specified (required for sub-admins)" : "Keine Gruppe angegeben (erforderlich für Unteradministratoren)",
+ "Sub-admin group does not exist" : "Die Unteradministratoren-Gruppe existiert nicht",
+ "Cannot create sub-admins for admin group" : "Kann keine Unteradministratoren für die Administrationsgruppe erstellen",
+ "No permissions to promote sub-admins" : "Keine Berechtigungen, um Unteradministratoren zu ernennen",
+ "Invalid password value" : "Ungültiger Passwort-Wert",
+ "An email address is required, to send a password link to the user." : "Um dem Benutzer einen Passwortlink zu senden, ist eine E-Mail-Adresse erforderlich.",
+ "Required email address was not provided" : "Erforderliche E-Mail-Adresse wurde nicht angegeben",
+ "User creation failed" : "Benutzererstellung fehlgeschlagen",
+ "Invalid quota value: %1$s" : "Ungültiger Wert für Speicherkontigent: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ungültiger Wert für Speicherkontigent. %1$s überschreitet das maximale Kontigent",
+ "Unlimited quota is forbidden on this instance" : "Unbegrenztes Speicherkontigent ist auf dieser Instanz unzulässig",
+ "Setting the password is not supported by the users backend" : "Das Passwort kann nicht über das Benutzerbackend festgelegt werden",
+ "Invalid language" : "Ungültige Sprache",
+ "Invalid locale" : "Ungültige Lokalisierung",
+ "Invalid first day of week" : "Ungültiger erster Tag der Woche",
+ "Cannot remove yourself from the admin group" : "Sie können sich nicht selbst aus der Administrationsgruppe entfernen",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Sie können sich nicht selbst aus dieser Gruppe entfernen, da Sie ein Unteradministrator sind",
+ "Not viable to remove user from the last group you are sub-admin of" : "Den Benutzer aus der letzten Gruppe zu entfernen, in der Sie Unteradministrator sind ist nicht möglich.",
+ "User does not exist" : "Benutzer existiert nicht",
+ "Group does not exist" : "Gruppe existiert nicht",
+ "User is not a sub-admin of this group" : "Benutzer ist kein Unteradministrator dieser Gruppe",
+ "Email address not available" : "E-Mail-Adresse nicht verfügbar",
+ "Sending email failed" : "Senden der E-Mail ist fehlgeschlagen",
+ "Email confirmation" : "E-Mail-Bestätigung",
+ "To enable the email address %s please click the button below." : "Um die E-Mail-Adresse %s zu bestätigen, klicken Sie bitte auf die untenstehende Schaltfläche.",
+ "Confirm" : "Bestätigen",
+ "Email was already removed from account and cannot be confirmed anymore." : "Diese E-Mail-Adresse wurde bereits aus dem Konto entfernt und kann nicht mehr bestätigt werden.",
+ "Could not verify mail because the token is expired." : "Die E-Mail-Adresse konnte aufgrund eines abgelaufenen Tokens nicht zurückgesetzt werden",
+ "Could not verify mail because the token is invalid." : "Das Passwort konnte aufgrund eines ungültigen Tokens nicht bestätigt werden",
+ "An unexpected error occurred. Please contact your admin." : "Es ist ein unerwarteter Fehler aufgetreten, bitte kontaktieren Sie Ihre Administration.",
+ "Email confirmation successful" : "E-Mail-Adresse wurde bestätgt",
+ "Provisioning API" : "Bereitstellung-API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Diese Applikation stellt einen Satz von APIs für externe Systeme zur Verfügung um Konten, Gruppen und Apps zu verwalten.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Diese Anwendung aktiviert eine Reihe von APIs, mit denen externe Systeme Konten erstellen, bearbeiten, löschen und abfragen können\n\t\tAttribute, Gruppen abfragen, festlegen und entfernen, Kontingent festlegen und Gesamtspeicher abfragen, der in Nextcloud verwendet wird. Gruppenadministrationskonto\n\t\tSie können auch Nextcloud abfragen und dieselben Funktionen wie ein Administrator für von ihnen verwaltete Gruppen ausführen. Die API ermöglicht auch\n\t\tEin Administrator, der nach aktiven Nextcloud-Anwendungen und Anwendungsinformationen fragt und eine App entfernt aktiviert oder deaktiviert.\n\t\tSobald die App aktiviert ist, können HTTP-Anforderungen über einen Basic Auth-Header verwendet werden, um eine der Funktionen auszuführen\n\t\toben aufgelistet. Weitere Informationen finden Sie in der Bereitstellung-API Dokumentation, einschließlich Beispielaufrufen\n\t\tund Serverantworten."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/en_GB.js b/apps/provisioning_api/l10n/en_GB.js
new file mode 100644
index 00000000000..3469fee516d
--- /dev/null
+++ b/apps/provisioning_api/l10n/en_GB.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Logged in account must be an administrator or have authorization to edit this setting.",
+ "Could not create non-existing user ID" : "Could not create non-existing user ID",
+ "User already exists" : "User already exists",
+ "Group %1$s does not exist" : "Group %1$s does not exist",
+ "Insufficient privileges for group %1$s" : "Insufficient privileges for group %1$s",
+ "No group specified (required for sub-admins)" : "No group specified (required for sub-admins)",
+ "Sub-admin group does not exist" : "Sub-admin group does not exist",
+ "Cannot create sub-admins for admin group" : "Cannot create sub-admins for admin group",
+ "No permissions to promote sub-admins" : "No permissions to promote sub-admins",
+ "Invalid password value" : "Invalid password value",
+ "An email address is required, to send a password link to the user." : "An email address is required, to send a password link to the user.",
+ "Required email address was not provided" : "Required email address was not provided",
+ "User creation failed" : "User creation failed",
+ "Invalid quota value: %1$s" : "Invalid quota value: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Invalid quota value. %1$s is exceeding the maximum quota",
+ "Unlimited quota is forbidden on this instance" : "Unlimited quota is forbidden on this instance",
+ "Setting the password is not supported by the users backend" : "Setting the password is not supported by the users backend",
+ "Invalid language" : "Invalid language",
+ "Invalid locale" : "Invalid locale",
+ "Invalid first day of week" : "Invalid first day of week",
+ "Cannot remove yourself from the admin group" : "Cannot remove yourself from the admin group",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Cannot remove yourself from this group as you are a sub-admin",
+ "Not viable to remove user from the last group you are sub-admin of" : "Not viable to remove user from the last group you are sub-admin of",
+ "User does not exist" : "User does not exist",
+ "Group does not exist" : "Group does not exist",
+ "User is not a sub-admin of this group" : "User is not a sub-admin of this group",
+ "Email address not available" : "Email address not available",
+ "Sending email failed" : "Sending email failed",
+ "Email confirmation" : "Email confirmation",
+ "To enable the email address %s please click the button below." : "To enable the email address %s please click the button below.",
+ "Confirm" : "Confirm",
+ "Email was already removed from account and cannot be confirmed anymore." : "Email was already removed from account and cannot be confirmed anymore.",
+ "Could not verify mail because the token is expired." : "Could not verify mail because the token is expired.",
+ "Could not verify mail because the token is invalid." : "Could not verify mail because the token is invalid.",
+ "An unexpected error occurred. Please contact your admin." : "An unexpected error occurred. Please contact your admin.",
+ "Email confirmation successful" : "Email confirmation successful",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "This application enables a set of APIs that external systems can use to manage accounts, groups and apps.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/en_GB.json b/apps/provisioning_api/l10n/en_GB.json
new file mode 100644
index 00000000000..6a6898da4c4
--- /dev/null
+++ b/apps/provisioning_api/l10n/en_GB.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Logged in account must be an administrator or have authorization to edit this setting.",
+ "Could not create non-existing user ID" : "Could not create non-existing user ID",
+ "User already exists" : "User already exists",
+ "Group %1$s does not exist" : "Group %1$s does not exist",
+ "Insufficient privileges for group %1$s" : "Insufficient privileges for group %1$s",
+ "No group specified (required for sub-admins)" : "No group specified (required for sub-admins)",
+ "Sub-admin group does not exist" : "Sub-admin group does not exist",
+ "Cannot create sub-admins for admin group" : "Cannot create sub-admins for admin group",
+ "No permissions to promote sub-admins" : "No permissions to promote sub-admins",
+ "Invalid password value" : "Invalid password value",
+ "An email address is required, to send a password link to the user." : "An email address is required, to send a password link to the user.",
+ "Required email address was not provided" : "Required email address was not provided",
+ "User creation failed" : "User creation failed",
+ "Invalid quota value: %1$s" : "Invalid quota value: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Invalid quota value. %1$s is exceeding the maximum quota",
+ "Unlimited quota is forbidden on this instance" : "Unlimited quota is forbidden on this instance",
+ "Setting the password is not supported by the users backend" : "Setting the password is not supported by the users backend",
+ "Invalid language" : "Invalid language",
+ "Invalid locale" : "Invalid locale",
+ "Invalid first day of week" : "Invalid first day of week",
+ "Cannot remove yourself from the admin group" : "Cannot remove yourself from the admin group",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Cannot remove yourself from this group as you are a sub-admin",
+ "Not viable to remove user from the last group you are sub-admin of" : "Not viable to remove user from the last group you are sub-admin of",
+ "User does not exist" : "User does not exist",
+ "Group does not exist" : "Group does not exist",
+ "User is not a sub-admin of this group" : "User is not a sub-admin of this group",
+ "Email address not available" : "Email address not available",
+ "Sending email failed" : "Sending email failed",
+ "Email confirmation" : "Email confirmation",
+ "To enable the email address %s please click the button below." : "To enable the email address %s please click the button below.",
+ "Confirm" : "Confirm",
+ "Email was already removed from account and cannot be confirmed anymore." : "Email was already removed from account and cannot be confirmed anymore.",
+ "Could not verify mail because the token is expired." : "Could not verify mail because the token is expired.",
+ "Could not verify mail because the token is invalid." : "Could not verify mail because the token is invalid.",
+ "An unexpected error occurred. Please contact your admin." : "An unexpected error occurred. Please contact your admin.",
+ "Email confirmation successful" : "Email confirmation successful",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "This application enables a set of APIs that external systems can use to manage accounts, groups and apps.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/es.js b/apps/provisioning_api/l10n/es.js
new file mode 100644
index 00000000000..c8706c3cde7
--- /dev/null
+++ b/apps/provisioning_api/l10n/es.js
@@ -0,0 +1,41 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "El usuario que ha iniciado sesión debe ser un administrador o tener autorización para editar esta configuración.",
+ "Could not create non-existing user ID" : "No se pudo crear el ID de usuario no existente",
+ "User already exists" : "El usuario ya existe",
+ "Group %1$s does not exist" : "El grupo %1$s no existe",
+ "Insufficient privileges for group %1$s" : "Privilegios insuficientes para el grupo %1$s",
+ "No group specified (required for sub-admins)" : "No se especificó ningún grupo (requerido para subadministradores)",
+ "Sub-admin group does not exist" : "El grupo subadministrador no existe",
+ "Cannot create sub-admins for admin group" : "No se pueden crear subadministradores para el grupo admin",
+ "No permissions to promote sub-admins" : "No tiene permisos para promover subadministradores",
+ "Invalid password value" : "Valor de contraseña inválido",
+ "Required email address was not provided" : "La dirección de correo electrónico requerida no fue proporcionada",
+ "Invalid quota value: %1$s" : "Valor de cuota inválido: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valor de cuota inválido. %1$s excede la cuota máxima",
+ "Unlimited quota is forbidden on this instance" : "La cuota ilimitada está prohibida en esta instancia",
+ "Setting the password is not supported by the users backend" : "El backend de los usuarios no soporta establecer la contraseña",
+ "Invalid language" : "Idioma inválido",
+ "Invalid locale" : "Configuración regional inválida",
+ "Cannot remove yourself from the admin group" : "No se puede remover a Ud. mismo del grupo de administración",
+ "Cannot remove yourself from this group as you are a sub-admin" : "No se puede remover así mismo de este grupo dado que Ud. es un subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "No es viable remover el usuario del último grupo del que Ud. es subadministrador",
+ "User does not exist" : "El usuario no existe",
+ "Group does not exist" : "El grupo no existe",
+ "User is not a sub-admin of this group" : "El usuario no es un subadministrador de este grupo",
+ "Email address not available" : "Dirección de correo electrónico no disponible",
+ "Sending email failed" : "Falló el envío del correo electrónico",
+ "Email confirmation" : "Confirmación del correo electrónico",
+ "To enable the email address %s please click the button below." : "Para habilitar la dirección de correo electrónico %s , por favor, haga clic en el botón a continuación.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "El correo electrónico ha sido eliminado de la cuenta y ya no puede ser confirmado.",
+ "Could not verify mail because the token is expired." : "No se ha podido verificar el correo electrónico porque el token ha expirado.",
+ "Could not verify mail because the token is invalid." : "No se ha podido verificar el correo electrónico porque el token es inválido.",
+ "An unexpected error occurred. Please contact your admin." : "Ha ocurrido un error inesperado. Por favor contacte a su administrador.",
+ "Email confirmation successful" : "Correo electrónico confirmado con éxito",
+ "Provisioning API" : "API de aprovisionamiento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación habilita un conjunto de APIs que los sistemas externos pueden usar para administrar usuarios, grupos y aplicaciones.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Esta aplicación habilita una serie de APIs que pueden ser usadas por sistemas externos para crear, editar, eliminar y seleccionar atributos\n\t\tde usuarios; seleccionar, configurar y eliminar grupos, establecer cuotas y consultar el almacenamiento total usado en Nextcloud. Las cuentas administradoras de grupos\n\t\ttambién pueden buscar en Nextcloud y realizar las mismas funciones como administrador para los grupos que manejan. La API también permite\n\t\ta un administrador que busque aplicaciones activas en Nextcloud, información de las apps, y activar o desactivar remotamente una app.\n\t\tUna vez que se activa la app, se pueden usar peticiones HTTP vía un encabezado Basic Auth para realizar cualesquiera de las funciones\n\t\t listadas anteriormente. Más información disponible en la documentación de la API de aprovisionamiento, incluyendo llamadas de ejemplo\n\t\ty respuestas del servidor."
+},
+"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/provisioning_api/l10n/es.json b/apps/provisioning_api/l10n/es.json
new file mode 100644
index 00000000000..791714eae46
--- /dev/null
+++ b/apps/provisioning_api/l10n/es.json
@@ -0,0 +1,39 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "El usuario que ha iniciado sesión debe ser un administrador o tener autorización para editar esta configuración.",
+ "Could not create non-existing user ID" : "No se pudo crear el ID de usuario no existente",
+ "User already exists" : "El usuario ya existe",
+ "Group %1$s does not exist" : "El grupo %1$s no existe",
+ "Insufficient privileges for group %1$s" : "Privilegios insuficientes para el grupo %1$s",
+ "No group specified (required for sub-admins)" : "No se especificó ningún grupo (requerido para subadministradores)",
+ "Sub-admin group does not exist" : "El grupo subadministrador no existe",
+ "Cannot create sub-admins for admin group" : "No se pueden crear subadministradores para el grupo admin",
+ "No permissions to promote sub-admins" : "No tiene permisos para promover subadministradores",
+ "Invalid password value" : "Valor de contraseña inválido",
+ "Required email address was not provided" : "La dirección de correo electrónico requerida no fue proporcionada",
+ "Invalid quota value: %1$s" : "Valor de cuota inválido: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valor de cuota inválido. %1$s excede la cuota máxima",
+ "Unlimited quota is forbidden on this instance" : "La cuota ilimitada está prohibida en esta instancia",
+ "Setting the password is not supported by the users backend" : "El backend de los usuarios no soporta establecer la contraseña",
+ "Invalid language" : "Idioma inválido",
+ "Invalid locale" : "Configuración regional inválida",
+ "Cannot remove yourself from the admin group" : "No se puede remover a Ud. mismo del grupo de administración",
+ "Cannot remove yourself from this group as you are a sub-admin" : "No se puede remover así mismo de este grupo dado que Ud. es un subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "No es viable remover el usuario del último grupo del que Ud. es subadministrador",
+ "User does not exist" : "El usuario no existe",
+ "Group does not exist" : "El grupo no existe",
+ "User is not a sub-admin of this group" : "El usuario no es un subadministrador de este grupo",
+ "Email address not available" : "Dirección de correo electrónico no disponible",
+ "Sending email failed" : "Falló el envío del correo electrónico",
+ "Email confirmation" : "Confirmación del correo electrónico",
+ "To enable the email address %s please click the button below." : "Para habilitar la dirección de correo electrónico %s , por favor, haga clic en el botón a continuación.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "El correo electrónico ha sido eliminado de la cuenta y ya no puede ser confirmado.",
+ "Could not verify mail because the token is expired." : "No se ha podido verificar el correo electrónico porque el token ha expirado.",
+ "Could not verify mail because the token is invalid." : "No se ha podido verificar el correo electrónico porque el token es inválido.",
+ "An unexpected error occurred. Please contact your admin." : "Ha ocurrido un error inesperado. Por favor contacte a su administrador.",
+ "Email confirmation successful" : "Correo electrónico confirmado con éxito",
+ "Provisioning API" : "API de aprovisionamiento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación habilita un conjunto de APIs que los sistemas externos pueden usar para administrar usuarios, grupos y aplicaciones.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Esta aplicación habilita una serie de APIs que pueden ser usadas por sistemas externos para crear, editar, eliminar y seleccionar atributos\n\t\tde usuarios; seleccionar, configurar y eliminar grupos, establecer cuotas y consultar el almacenamiento total usado en Nextcloud. Las cuentas administradoras de grupos\n\t\ttambién pueden buscar en Nextcloud y realizar las mismas funciones como administrador para los grupos que manejan. La API también permite\n\t\ta un administrador que busque aplicaciones activas en Nextcloud, información de las apps, y activar o desactivar remotamente una app.\n\t\tUna vez que se activa la app, se pueden usar peticiones HTTP vía un encabezado Basic Auth para realizar cualesquiera de las funciones\n\t\t listadas anteriormente. Más información disponible en la documentación de la API de aprovisionamiento, incluyendo llamadas de ejemplo\n\t\ty respuestas del servidor."
+},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/es_MX.js b/apps/provisioning_api/l10n/es_MX.js
new file mode 100644
index 00000000000..16162a08a3b
--- /dev/null
+++ b/apps/provisioning_api/l10n/es_MX.js
@@ -0,0 +1,42 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "El usuario que ha iniciado sesión debe ser un administrador o tener autorización para editar esta configuración.",
+ "Could not create non-existing user ID" : "No se pudo crear el identificador de usuario no existente",
+ "User already exists" : "El usuario ya existe",
+ "Group %1$s does not exist" : "El grupo %1$s no existe",
+ "Insufficient privileges for group %1$s" : "Privilegios insuficientes para el grupo %1$s",
+ "No group specified (required for sub-admins)" : "No se especificó ningún grupo (requerido para subadministradores)",
+ "Sub-admin group does not exist" : "El grupo subadministrador no existe",
+ "Cannot create sub-admins for admin group" : "No se pueden crear subadministradores para el grupo administrador",
+ "No permissions to promote sub-admins" : "Sin permisos para promover subadministradores",
+ "Invalid password value" : "Valor de contraseña inválido",
+ "Required email address was not provided" : "La dirección de correo electrónico requerido no fue proporcionado",
+ "Invalid quota value: %1$s" : "Valor de cuota inválido: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valor de cuota inválido. %1$s excede la cuota máxima",
+ "Unlimited quota is forbidden on this instance" : "La cuota ilimitada está prohibida en esta instancia",
+ "Setting the password is not supported by the users backend" : "El backend de los usuarios no soporta establecer la contraseña",
+ "Invalid language" : "Idioma inválido",
+ "Invalid locale" : "Configuración regional inválida",
+ "Invalid first day of week" : "Día de inicio de semana inválido",
+ "Cannot remove yourself from the admin group" : "No se puede remover a sí mismo del grupo administrador",
+ "Cannot remove yourself from this group as you are a sub-admin" : "No se puede remover así mismo de este grupo dado que es un subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "No es viable remover el usuario del último grupo que es subadministrador",
+ "User does not exist" : "El usuario no existe",
+ "Group does not exist" : "El grupo no existe",
+ "User is not a sub-admin of this group" : "El usuario no es un subadministrador de este grupo",
+ "Email address not available" : "Dirección de correo electrónico no disponible",
+ "Sending email failed" : "Falló el envío del correo electrónico",
+ "Email confirmation" : "Confirmación del correo electrónico",
+ "To enable the email address %s please click the button below." : "Para habilitar la dirección de correo electrónico %s, por favor, haga clic en el botón de abajo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "El correo electrónico ya fue eliminado de la cuenta y ya no puede ser confirmado.",
+ "Could not verify mail because the token is expired." : "No se pudo verificar el correo porque el token ha caducado.",
+ "Could not verify mail because the token is invalid." : "No se pudo verificar el correo porque el token es inválido.",
+ "An unexpected error occurred. Please contact your admin." : "Ocurrió un error inesperado. Por favor, contacte a su administrador.",
+ "Email confirmation successful" : "Confirmación del correo electrónico exitosa",
+ "Provisioning API" : "API de aprovisionamiento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación habilita un conjunto de APIs que los sistemas externos pueden usar para administrar usuarios, grupos y aplicaciones.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Esta aplicación habilita un conjunto de APIs que pueden ser usadas por sistemas externos para crear, editar, eliminar y seleccionar atributos\n\t\tde usuarios; seleccionar, configurar y eliminar grupos, establecer cuotas y consultar el almacenamiento total usado en Nextcloud. Las cuentas administradoras de grupos\n\t\ttambién pueden buscar en Nextcloud y desempeñar las mismas funciones como administrador para los grupos que administran. La API también permite\n\t\ta un administrador que busque aplicaciones activas en Nextcloud, información de la aplicación, y activar o desactivar una aplicación remotamente.\n\t\tUna vez activada la aplicación, se pueden usar peticiones HTTP mediante un encabezado Basic Auth para realizar cualquiera de las funciones\n\t\t listadas anteriormente. Más información disponible en la documentación de la API de aprovisionamiento, incluyendo llamadas de ejemplo\n\t\ty respuestas del servidor."
+},
+"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/provisioning_api/l10n/es_MX.json b/apps/provisioning_api/l10n/es_MX.json
new file mode 100644
index 00000000000..9acf9efa87e
--- /dev/null
+++ b/apps/provisioning_api/l10n/es_MX.json
@@ -0,0 +1,40 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "El usuario que ha iniciado sesión debe ser un administrador o tener autorización para editar esta configuración.",
+ "Could not create non-existing user ID" : "No se pudo crear el identificador de usuario no existente",
+ "User already exists" : "El usuario ya existe",
+ "Group %1$s does not exist" : "El grupo %1$s no existe",
+ "Insufficient privileges for group %1$s" : "Privilegios insuficientes para el grupo %1$s",
+ "No group specified (required for sub-admins)" : "No se especificó ningún grupo (requerido para subadministradores)",
+ "Sub-admin group does not exist" : "El grupo subadministrador no existe",
+ "Cannot create sub-admins for admin group" : "No se pueden crear subadministradores para el grupo administrador",
+ "No permissions to promote sub-admins" : "Sin permisos para promover subadministradores",
+ "Invalid password value" : "Valor de contraseña inválido",
+ "Required email address was not provided" : "La dirección de correo electrónico requerido no fue proporcionado",
+ "Invalid quota value: %1$s" : "Valor de cuota inválido: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valor de cuota inválido. %1$s excede la cuota máxima",
+ "Unlimited quota is forbidden on this instance" : "La cuota ilimitada está prohibida en esta instancia",
+ "Setting the password is not supported by the users backend" : "El backend de los usuarios no soporta establecer la contraseña",
+ "Invalid language" : "Idioma inválido",
+ "Invalid locale" : "Configuración regional inválida",
+ "Invalid first day of week" : "Día de inicio de semana inválido",
+ "Cannot remove yourself from the admin group" : "No se puede remover a sí mismo del grupo administrador",
+ "Cannot remove yourself from this group as you are a sub-admin" : "No se puede remover así mismo de este grupo dado que es un subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "No es viable remover el usuario del último grupo que es subadministrador",
+ "User does not exist" : "El usuario no existe",
+ "Group does not exist" : "El grupo no existe",
+ "User is not a sub-admin of this group" : "El usuario no es un subadministrador de este grupo",
+ "Email address not available" : "Dirección de correo electrónico no disponible",
+ "Sending email failed" : "Falló el envío del correo electrónico",
+ "Email confirmation" : "Confirmación del correo electrónico",
+ "To enable the email address %s please click the button below." : "Para habilitar la dirección de correo electrónico %s, por favor, haga clic en el botón de abajo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "El correo electrónico ya fue eliminado de la cuenta y ya no puede ser confirmado.",
+ "Could not verify mail because the token is expired." : "No se pudo verificar el correo porque el token ha caducado.",
+ "Could not verify mail because the token is invalid." : "No se pudo verificar el correo porque el token es inválido.",
+ "An unexpected error occurred. Please contact your admin." : "Ocurrió un error inesperado. Por favor, contacte a su administrador.",
+ "Email confirmation successful" : "Confirmación del correo electrónico exitosa",
+ "Provisioning API" : "API de aprovisionamiento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación habilita un conjunto de APIs que los sistemas externos pueden usar para administrar usuarios, grupos y aplicaciones.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Esta aplicación habilita un conjunto de APIs que pueden ser usadas por sistemas externos para crear, editar, eliminar y seleccionar atributos\n\t\tde usuarios; seleccionar, configurar y eliminar grupos, establecer cuotas y consultar el almacenamiento total usado en Nextcloud. Las cuentas administradoras de grupos\n\t\ttambién pueden buscar en Nextcloud y desempeñar las mismas funciones como administrador para los grupos que administran. La API también permite\n\t\ta un administrador que busque aplicaciones activas en Nextcloud, información de la aplicación, y activar o desactivar una aplicación remotamente.\n\t\tUna vez activada la aplicación, se pueden usar peticiones HTTP mediante un encabezado Basic Auth para realizar cualquiera de las funciones\n\t\t listadas anteriormente. Más información disponible en la documentación de la API de aprovisionamiento, incluyendo llamadas de ejemplo\n\t\ty respuestas del servidor."
+},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/et_EE.js b/apps/provisioning_api/l10n/et_EE.js
new file mode 100644
index 00000000000..2081f8c467c
--- /dev/null
+++ b/apps/provisioning_api/l10n/et_EE.js
@@ -0,0 +1,41 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Sisselogitud kasutajakonto peab olema peakasutajat või omama eraldi õigust selle seadustuse muutmiseks.",
+ "User already exists" : "Kasutaja on juba olemas",
+ "Group %1$s does not exist" : "%1$s gruppi pole olemas",
+ "Insufficient privileges for group %1$s" : "%1$s grupi jaoks pole pole piisavalt õigusi",
+ "No group specified (required for sub-admins)" : "Ühtegi gruppi pole määratud (vajalik peakasutajate alamgrupi puhul)",
+ "Sub-admin group does not exist" : "Peakasutajate alamgruppi pole olemas",
+ "Cannot create sub-admins for admin group" : "Peakasutajate grupi alamgruppi loomine ei õnnestu",
+ "No permissions to promote sub-admins" : "Pole õigusi peakasutajat alamgruppi määramiseks",
+ "Invalid password value" : "Vigane salasõna väärtus",
+ "An email address is required, to send a password link to the user." : "Salasõnalingi saatmiseks kasutajale on vajalik e-posti aadress.",
+ "Required email address was not provided" : "Vajalik e-posti aadress on lisamata",
+ "User creation failed" : "Kasutaja loomine ei õnnestunud",
+ "Invalid quota value: %1$s" : "Vigane kvoodi väärtus: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Vigane kvoodi väärtus. %1$s üledab maksimumkvoodi piiri",
+ "Unlimited quota is forbidden on this instance" : "Piiramatu kvoodi kasutamine on selles serveris keelatud",
+ "Setting the password is not supported by the users backend" : "Salasõna lisamine pole kasutajate taustateenuse poolt toetatud",
+ "Invalid language" : "Vigane keel",
+ "Invalid locale" : "Vigane lokaat",
+ "Invalid first day of week" : "Vigane nädala esimene päev",
+ "Cannot remove yourself from the admin group" : "Sa ei saa end peakasutajate grupist eemaldada",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Kuna oled peakasutajate alamgrupi liige, siis sa ei saa end eemaldada",
+ "Not viable to remove user from the last group you are sub-admin of" : "Pole mõistlik eemaldada kasutajat viimasest grupist, kus oled peakasutajate alamgrupi liige",
+ "User does not exist" : "Kasutajat pole olemas",
+ "Group does not exist" : "Gruppi pole olemas",
+ "User is not a sub-admin of this group" : "Kasutaja pole selle grupi peakasutajate alamgrupi liige",
+ "Email address not available" : "E-posti aadress pole saadaval",
+ "Sending email failed" : "E-kirja saatmine ei õnnestunud",
+ "Email confirmation" : "E-posti aadressi kinnitamine",
+ "To enable the email address %s please click the button below." : "%s e-posti aadressi kinnitamiseks palun klõpsi järgnevat nuppu.",
+ "Confirm" : "Kinnita",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-posti aadress on kasutaja andmetest eemaldatud ja seda ei saa enam kinnitada.",
+ "Could not verify mail because the token is expired." : "Kuna tunnusluba on aegunud, siis e-posti aadressi kinnitamine pole võimalik.",
+ "Could not verify mail because the token is invalid." : "Kuna tunnusluba on vigane, siis e-posti aadressi kinnitamine pole võimalik.",
+ "An unexpected error occurred. Please contact your admin." : "Tekkis ootamatu viga. Palun võta ühendust peakasutajaga.",
+ "Email confirmation successful" : "E-posti aadressi kinnitamine õnnestus.",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "See rakendus võtab kasutusele sellised API-d mis võimaldavad välistel süsteemidel hallata kasutajakontosid, gruppe ja rakendusi."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/et_EE.json b/apps/provisioning_api/l10n/et_EE.json
new file mode 100644
index 00000000000..f339e224be0
--- /dev/null
+++ b/apps/provisioning_api/l10n/et_EE.json
@@ -0,0 +1,39 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Sisselogitud kasutajakonto peab olema peakasutajat või omama eraldi õigust selle seadustuse muutmiseks.",
+ "User already exists" : "Kasutaja on juba olemas",
+ "Group %1$s does not exist" : "%1$s gruppi pole olemas",
+ "Insufficient privileges for group %1$s" : "%1$s grupi jaoks pole pole piisavalt õigusi",
+ "No group specified (required for sub-admins)" : "Ühtegi gruppi pole määratud (vajalik peakasutajate alamgrupi puhul)",
+ "Sub-admin group does not exist" : "Peakasutajate alamgruppi pole olemas",
+ "Cannot create sub-admins for admin group" : "Peakasutajate grupi alamgruppi loomine ei õnnestu",
+ "No permissions to promote sub-admins" : "Pole õigusi peakasutajat alamgruppi määramiseks",
+ "Invalid password value" : "Vigane salasõna väärtus",
+ "An email address is required, to send a password link to the user." : "Salasõnalingi saatmiseks kasutajale on vajalik e-posti aadress.",
+ "Required email address was not provided" : "Vajalik e-posti aadress on lisamata",
+ "User creation failed" : "Kasutaja loomine ei õnnestunud",
+ "Invalid quota value: %1$s" : "Vigane kvoodi väärtus: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Vigane kvoodi väärtus. %1$s üledab maksimumkvoodi piiri",
+ "Unlimited quota is forbidden on this instance" : "Piiramatu kvoodi kasutamine on selles serveris keelatud",
+ "Setting the password is not supported by the users backend" : "Salasõna lisamine pole kasutajate taustateenuse poolt toetatud",
+ "Invalid language" : "Vigane keel",
+ "Invalid locale" : "Vigane lokaat",
+ "Invalid first day of week" : "Vigane nädala esimene päev",
+ "Cannot remove yourself from the admin group" : "Sa ei saa end peakasutajate grupist eemaldada",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Kuna oled peakasutajate alamgrupi liige, siis sa ei saa end eemaldada",
+ "Not viable to remove user from the last group you are sub-admin of" : "Pole mõistlik eemaldada kasutajat viimasest grupist, kus oled peakasutajate alamgrupi liige",
+ "User does not exist" : "Kasutajat pole olemas",
+ "Group does not exist" : "Gruppi pole olemas",
+ "User is not a sub-admin of this group" : "Kasutaja pole selle grupi peakasutajate alamgrupi liige",
+ "Email address not available" : "E-posti aadress pole saadaval",
+ "Sending email failed" : "E-kirja saatmine ei õnnestunud",
+ "Email confirmation" : "E-posti aadressi kinnitamine",
+ "To enable the email address %s please click the button below." : "%s e-posti aadressi kinnitamiseks palun klõpsi järgnevat nuppu.",
+ "Confirm" : "Kinnita",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-posti aadress on kasutaja andmetest eemaldatud ja seda ei saa enam kinnitada.",
+ "Could not verify mail because the token is expired." : "Kuna tunnusluba on aegunud, siis e-posti aadressi kinnitamine pole võimalik.",
+ "Could not verify mail because the token is invalid." : "Kuna tunnusluba on vigane, siis e-posti aadressi kinnitamine pole võimalik.",
+ "An unexpected error occurred. Please contact your admin." : "Tekkis ootamatu viga. Palun võta ühendust peakasutajaga.",
+ "Email confirmation successful" : "E-posti aadressi kinnitamine õnnestus.",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "See rakendus võtab kasutusele sellised API-d mis võimaldavad välistel süsteemidel hallata kasutajakontosid, gruppe ja rakendusi."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/eu.js b/apps/provisioning_api/l10n/eu.js
new file mode 100644
index 00000000000..528224b780b
--- /dev/null
+++ b/apps/provisioning_api/l10n/eu.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Saioa hasitako erabiltzaileak administratzailea edo ezarpen hau editatzeko baimena duena izan behar du.",
+ "Could not create non-existing user ID" : "Ezin izan da sortu existitzen ez den erabiltzailearen IDa",
+ "User already exists" : "Erabiltzailea dagoeneko existitzen da",
+ "Group %1$s does not exist" : "%1$s taldea ez da existitzen",
+ "Insufficient privileges for group %1$s" : "%1$s taldeak baimen gutxiegi dauzka",
+ "No group specified (required for sub-admins)" : "Ez da talderik zehaztu (beharrezkoa da azpi-administratzaileentzat)",
+ "Sub-admin group does not exist" : "Azpi-administratzaileen taldea ez da existitzen",
+ "Cannot create sub-admins for admin group" : "Ezin da azpi-administratzailerik sortu administratzaile taldearentzat",
+ "No permissions to promote sub-admins" : "Ez duzu baimenik azpi-administratzaileak mailaz igotzeko",
+ "Invalid password value" : "Pasahitz baliogabea",
+ "An email address is required, to send a password link to the user." : "Helbide elektroniko bat behar da erabiltzaileari pasahitz-esteka bat bidaltzeko.",
+ "Required email address was not provided" : "Beharrezkoa den helbide elektronikoa falta da",
+ "Invalid quota value: %1$s" : "Kuota baliogabea: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Kuota baliogabea. %1$s kuota maximotik gain dago",
+ "Unlimited quota is forbidden on this instance" : "Kuota mugagabea debekatuta dago instantzia honetan",
+ "Setting the password is not supported by the users backend" : "Erabiltzailearen atzeko aldeak ez du onartzen pasahitza ezartzea",
+ "Invalid language" : "Hizkuntza baliogabea",
+ "Invalid locale" : "Eskualde ezarpen baliogabea",
+ "Invalid first day of week" : "Asteko lehen egun baliogabea",
+ "Cannot remove yourself from the admin group" : "Ezin duzu zeure burua kendu admin taldetik",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Ezin duzu zeure burua talde honetatik kendu, azpi-administratzailea zarelako",
+ "Not viable to remove user from the last group you are sub-admin of" : "Ez dago modurik azpi-administratzaile zaren talde horretatik erabiltzailea kentzeko",
+ "User does not exist" : "Erabiltzailea ez da existitzen",
+ "Group does not exist" : "Taldea ez da existitzen",
+ "User is not a sub-admin of this group" : "Erabiltzailea ez da talde honetako azpi-administratzailea",
+ "Email address not available" : "Helbide elektronikoa ez dago erabilgarri",
+ "Sending email failed" : "Mezu elektronikoa bidaltzeak huts egin du",
+ "Email confirmation" : "Posta elektronikoaren berrespena",
+ "To enable the email address %s please click the button below." : "%shelbide elektronikoa gaitzeko, egin klik beheko botoian.",
+ "Confirm" : "Berretsi",
+ "Email was already removed from account and cannot be confirmed anymore." : "Posta elektronikoa kontutik kenduta dago eta ezin da berretsi.",
+ "Could not verify mail because the token is expired." : "Ezin izan da posta egiaztatu, token-a iraungi delako.",
+ "Could not verify mail because the token is invalid." : "Ezin izan da posta egiaztatu, tokena baliogabea delako.",
+ "An unexpected error occurred. Please contact your admin." : "Ustekabeko errorea gertatu da. Jarri harremanetan zure administratzailearekin.",
+ "Email confirmation successful" : "Mezu elektronikoaren berrespena ongi egin da",
+ "Provisioning API" : "API hornitzen",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Aplikazio honek API multzo bat gaitzen du kanpoko sistemei aukera emanez kontuak, taldeak eta aplikazioak kudeatzeko. ",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Aplikazio honek gaitzen du kanpoko sistemek kontuak sortu, editatu, ezabatu eta kontsultatzeko erabili ditzaketen API multzo bat\n\t\tatributuak, kontsultak, taldeak ezarri eta kendu, kuota ezarri eta Nextcloud-en erabilitako biltegiratze osoa kontsultatu. Taldeko administratzaileek\n\t\tNextcloud ere kontsulta dezakete eta administratzaile baten funtzio berdinak bete kudeatzen dituzten taldeentzako. APIak ere gaitzen du\n\t\tadministratzaile bat Nextcloud kontsultatzeko aplikazio aktiboak, aplikazioen informazioa eta aplikazio bat urrunetik gaitzeko edo desgaitzeko.\n\t\tAplikazioa gaituta dagoenean, HTTP eskaerak oinarrizko autentifikazio goiburu baten bidez erabili daitezke betetzeko\n\t\tgoian zerrendatuko edozein funtzio. Informazio gehiago eskuragarri dago API hornitze- dokumentazioan, adibide-deiak\n\t\teta zerbitzariaren erantzunak barne."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/eu.json b/apps/provisioning_api/l10n/eu.json
new file mode 100644
index 00000000000..9ba4c5d3475
--- /dev/null
+++ b/apps/provisioning_api/l10n/eu.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Saioa hasitako erabiltzaileak administratzailea edo ezarpen hau editatzeko baimena duena izan behar du.",
+ "Could not create non-existing user ID" : "Ezin izan da sortu existitzen ez den erabiltzailearen IDa",
+ "User already exists" : "Erabiltzailea dagoeneko existitzen da",
+ "Group %1$s does not exist" : "%1$s taldea ez da existitzen",
+ "Insufficient privileges for group %1$s" : "%1$s taldeak baimen gutxiegi dauzka",
+ "No group specified (required for sub-admins)" : "Ez da talderik zehaztu (beharrezkoa da azpi-administratzaileentzat)",
+ "Sub-admin group does not exist" : "Azpi-administratzaileen taldea ez da existitzen",
+ "Cannot create sub-admins for admin group" : "Ezin da azpi-administratzailerik sortu administratzaile taldearentzat",
+ "No permissions to promote sub-admins" : "Ez duzu baimenik azpi-administratzaileak mailaz igotzeko",
+ "Invalid password value" : "Pasahitz baliogabea",
+ "An email address is required, to send a password link to the user." : "Helbide elektroniko bat behar da erabiltzaileari pasahitz-esteka bat bidaltzeko.",
+ "Required email address was not provided" : "Beharrezkoa den helbide elektronikoa falta da",
+ "Invalid quota value: %1$s" : "Kuota baliogabea: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Kuota baliogabea. %1$s kuota maximotik gain dago",
+ "Unlimited quota is forbidden on this instance" : "Kuota mugagabea debekatuta dago instantzia honetan",
+ "Setting the password is not supported by the users backend" : "Erabiltzailearen atzeko aldeak ez du onartzen pasahitza ezartzea",
+ "Invalid language" : "Hizkuntza baliogabea",
+ "Invalid locale" : "Eskualde ezarpen baliogabea",
+ "Invalid first day of week" : "Asteko lehen egun baliogabea",
+ "Cannot remove yourself from the admin group" : "Ezin duzu zeure burua kendu admin taldetik",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Ezin duzu zeure burua talde honetatik kendu, azpi-administratzailea zarelako",
+ "Not viable to remove user from the last group you are sub-admin of" : "Ez dago modurik azpi-administratzaile zaren talde horretatik erabiltzailea kentzeko",
+ "User does not exist" : "Erabiltzailea ez da existitzen",
+ "Group does not exist" : "Taldea ez da existitzen",
+ "User is not a sub-admin of this group" : "Erabiltzailea ez da talde honetako azpi-administratzailea",
+ "Email address not available" : "Helbide elektronikoa ez dago erabilgarri",
+ "Sending email failed" : "Mezu elektronikoa bidaltzeak huts egin du",
+ "Email confirmation" : "Posta elektronikoaren berrespena",
+ "To enable the email address %s please click the button below." : "%shelbide elektronikoa gaitzeko, egin klik beheko botoian.",
+ "Confirm" : "Berretsi",
+ "Email was already removed from account and cannot be confirmed anymore." : "Posta elektronikoa kontutik kenduta dago eta ezin da berretsi.",
+ "Could not verify mail because the token is expired." : "Ezin izan da posta egiaztatu, token-a iraungi delako.",
+ "Could not verify mail because the token is invalid." : "Ezin izan da posta egiaztatu, tokena baliogabea delako.",
+ "An unexpected error occurred. Please contact your admin." : "Ustekabeko errorea gertatu da. Jarri harremanetan zure administratzailearekin.",
+ "Email confirmation successful" : "Mezu elektronikoaren berrespena ongi egin da",
+ "Provisioning API" : "API hornitzen",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Aplikazio honek API multzo bat gaitzen du kanpoko sistemei aukera emanez kontuak, taldeak eta aplikazioak kudeatzeko. ",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Aplikazio honek gaitzen du kanpoko sistemek kontuak sortu, editatu, ezabatu eta kontsultatzeko erabili ditzaketen API multzo bat\n\t\tatributuak, kontsultak, taldeak ezarri eta kendu, kuota ezarri eta Nextcloud-en erabilitako biltegiratze osoa kontsultatu. Taldeko administratzaileek\n\t\tNextcloud ere kontsulta dezakete eta administratzaile baten funtzio berdinak bete kudeatzen dituzten taldeentzako. APIak ere gaitzen du\n\t\tadministratzaile bat Nextcloud kontsultatzeko aplikazio aktiboak, aplikazioen informazioa eta aplikazio bat urrunetik gaitzeko edo desgaitzeko.\n\t\tAplikazioa gaituta dagoenean, HTTP eskaerak oinarrizko autentifikazio goiburu baten bidez erabili daitezke betetzeko\n\t\tgoian zerrendatuko edozein funtzio. Informazio gehiago eskuragarri dago API hornitze- dokumentazioan, adibide-deiak\n\t\teta zerbitzariaren erantzunak barne."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/fr.js b/apps/provisioning_api/l10n/fr.js
new file mode 100644
index 00000000000..071d85c05dd
--- /dev/null
+++ b/apps/provisioning_api/l10n/fr.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Le compte connecté doit être un administrateur ou avoir l'autorisation de modifier ce paramètre.",
+ "Could not create non-existing user ID" : "IImpossible de créer un ID d'utilisateur inexistant",
+ "User already exists" : "Cet utilisateur existe déjà",
+ "Group %1$s does not exist" : "Le groupe %1$s n’existe pas",
+ "Insufficient privileges for group %1$s" : "Privilèges insuffisants pour le groupe %1$s",
+ "No group specified (required for sub-admins)" : "Aucun groupe spécifié (requis pour les sous-administrateurs)",
+ "Sub-admin group does not exist" : "Le groupe des sous-administrateurs n'existe pas",
+ "Cannot create sub-admins for admin group" : "Impossible de créer des sous-administrateurs pour le groupe des administrateurs",
+ "No permissions to promote sub-admins" : "Aucune autorisation pour promouvoir des sous-administrateurs",
+ "Invalid password value" : "Valeur de mot de passe invalide",
+ "An email address is required, to send a password link to the user." : "Une adresse email est requise pour envoyer un lien de mot de passe à l'utilisateur.",
+ "Required email address was not provided" : "L'adresse e-mail exigée n'a pas été fournie",
+ "Invalid quota value: %1$s" : "Valeur de quota invalide : %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valeur de quota invalide : %1$s dépasse le quota maximum",
+ "Unlimited quota is forbidden on this instance" : "Un quota illimité est interdit sur cette instance",
+ "Setting the password is not supported by the users backend" : "La définition du mot de passe n'est pas prise en charge par le backend des utilisateurs",
+ "Invalid language" : "Langue invalide",
+ "Invalid locale" : "Paramètres régionaux invalides",
+ "Invalid first day of week" : "Premier jour de la semaine invalide",
+ "Cannot remove yourself from the admin group" : "Impossible de vous retirer vous-même du groupe des administrateurs",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Impossible de vous retirer de ce groupe car vous êtes le sous-administrateur",
+ "Not viable to remove user from the last group you are sub-admin of" : "Il n'est pas possible de supprimer un utilisateur du dernier groupe dont vous êtes sous-administrateur",
+ "User does not exist" : "L'utilisateur n'existe pas",
+ "Group does not exist" : "Le groupe n'existe pas",
+ "User is not a sub-admin of this group" : "L'utilisateur n'est pas un sous-administrateur de ce groupe",
+ "Email address not available" : "Adresse e-mail indisponible ",
+ "Sending email failed" : "L'envoi de l'e-mail a échoué",
+ "Email confirmation" : "Confirmation par e-mail",
+ "To enable the email address %s please click the button below." : "Pour activer l'adresse e-mail %s, veuillez cliquer sur le bouton ci-dessous.",
+ "Confirm" : "Confirmer",
+ "Email was already removed from account and cannot be confirmed anymore." : "L'adresse e-mail a déjà été supprimée du compte et ne peut donc plus être confirmée.",
+ "Could not verify mail because the token is expired." : "Impossible de vérifier l'adresse e-mail car le jeton d'authentification est expiré.",
+ "Could not verify mail because the token is invalid." : "Impossible de vérifier l'adresse e-mail car le jeton d'authentification est invalide.",
+ "An unexpected error occurred. Please contact your admin." : "Une erreur inattendue est survenue. Veuillez contacter votre administrateur.",
+ "Email confirmation successful" : "Adresse e-mail confirmée avec succès.",
+ "Provisioning API" : "API de provisionnement",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Cette application active un ensemble d'API que les systèmes externes peuvent utiliser pour gérer les comptes, les groupes et les applications.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Cette application active un ensemble d'API qui peuvent être utilisées par un système externe pour créer, modifier, supprimer et rechercher des\n\t\tattributs de compte, rechercher, ajouter et retirer des groupes, fixer des quotas et rechercher l'espace de stockage total utilisé sur Nextcloud. Les administrateurs de groupe\n\t\tpeuvent aussi rechercher Nextcloud et accéder aux même fonctionnalités que les administrateurs pour les groupes dont ils ont la gestion. L'API permet aussi\n\t\tà un administrateur de rechercher les applications Nextcloud actives et les informations d'application ainsi que d'activer et désactiver les applications à distance.\n\t\tUne fois l'application activée, des requêtes HTTP peuvent être utilisées au moyen d'un entête Basic Auth pour exécuter chacune des fonctionnalités listées\n\t\tci-dessus. Des informations supplémentaires sont accessibles dans la documentation sur l'API de provisionnement, avec des exemples de demandes\n\t\tet réponses serveur."
+},
+"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/provisioning_api/l10n/fr.json b/apps/provisioning_api/l10n/fr.json
new file mode 100644
index 00000000000..c25a0b91c91
--- /dev/null
+++ b/apps/provisioning_api/l10n/fr.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Le compte connecté doit être un administrateur ou avoir l'autorisation de modifier ce paramètre.",
+ "Could not create non-existing user ID" : "IImpossible de créer un ID d'utilisateur inexistant",
+ "User already exists" : "Cet utilisateur existe déjà",
+ "Group %1$s does not exist" : "Le groupe %1$s n’existe pas",
+ "Insufficient privileges for group %1$s" : "Privilèges insuffisants pour le groupe %1$s",
+ "No group specified (required for sub-admins)" : "Aucun groupe spécifié (requis pour les sous-administrateurs)",
+ "Sub-admin group does not exist" : "Le groupe des sous-administrateurs n'existe pas",
+ "Cannot create sub-admins for admin group" : "Impossible de créer des sous-administrateurs pour le groupe des administrateurs",
+ "No permissions to promote sub-admins" : "Aucune autorisation pour promouvoir des sous-administrateurs",
+ "Invalid password value" : "Valeur de mot de passe invalide",
+ "An email address is required, to send a password link to the user." : "Une adresse email est requise pour envoyer un lien de mot de passe à l'utilisateur.",
+ "Required email address was not provided" : "L'adresse e-mail exigée n'a pas été fournie",
+ "Invalid quota value: %1$s" : "Valeur de quota invalide : %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valeur de quota invalide : %1$s dépasse le quota maximum",
+ "Unlimited quota is forbidden on this instance" : "Un quota illimité est interdit sur cette instance",
+ "Setting the password is not supported by the users backend" : "La définition du mot de passe n'est pas prise en charge par le backend des utilisateurs",
+ "Invalid language" : "Langue invalide",
+ "Invalid locale" : "Paramètres régionaux invalides",
+ "Invalid first day of week" : "Premier jour de la semaine invalide",
+ "Cannot remove yourself from the admin group" : "Impossible de vous retirer vous-même du groupe des administrateurs",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Impossible de vous retirer de ce groupe car vous êtes le sous-administrateur",
+ "Not viable to remove user from the last group you are sub-admin of" : "Il n'est pas possible de supprimer un utilisateur du dernier groupe dont vous êtes sous-administrateur",
+ "User does not exist" : "L'utilisateur n'existe pas",
+ "Group does not exist" : "Le groupe n'existe pas",
+ "User is not a sub-admin of this group" : "L'utilisateur n'est pas un sous-administrateur de ce groupe",
+ "Email address not available" : "Adresse e-mail indisponible ",
+ "Sending email failed" : "L'envoi de l'e-mail a échoué",
+ "Email confirmation" : "Confirmation par e-mail",
+ "To enable the email address %s please click the button below." : "Pour activer l'adresse e-mail %s, veuillez cliquer sur le bouton ci-dessous.",
+ "Confirm" : "Confirmer",
+ "Email was already removed from account and cannot be confirmed anymore." : "L'adresse e-mail a déjà été supprimée du compte et ne peut donc plus être confirmée.",
+ "Could not verify mail because the token is expired." : "Impossible de vérifier l'adresse e-mail car le jeton d'authentification est expiré.",
+ "Could not verify mail because the token is invalid." : "Impossible de vérifier l'adresse e-mail car le jeton d'authentification est invalide.",
+ "An unexpected error occurred. Please contact your admin." : "Une erreur inattendue est survenue. Veuillez contacter votre administrateur.",
+ "Email confirmation successful" : "Adresse e-mail confirmée avec succès.",
+ "Provisioning API" : "API de provisionnement",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Cette application active un ensemble d'API que les systèmes externes peuvent utiliser pour gérer les comptes, les groupes et les applications.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Cette application active un ensemble d'API qui peuvent être utilisées par un système externe pour créer, modifier, supprimer et rechercher des\n\t\tattributs de compte, rechercher, ajouter et retirer des groupes, fixer des quotas et rechercher l'espace de stockage total utilisé sur Nextcloud. Les administrateurs de groupe\n\t\tpeuvent aussi rechercher Nextcloud et accéder aux même fonctionnalités que les administrateurs pour les groupes dont ils ont la gestion. L'API permet aussi\n\t\tà un administrateur de rechercher les applications Nextcloud actives et les informations d'application ainsi que d'activer et désactiver les applications à distance.\n\t\tUne fois l'application activée, des requêtes HTTP peuvent être utilisées au moyen d'un entête Basic Auth pour exécuter chacune des fonctionnalités listées\n\t\tci-dessus. Des informations supplémentaires sont accessibles dans la documentation sur l'API de provisionnement, avec des exemples de demandes\n\t\tet réponses serveur."
+},"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/ga.js b/apps/provisioning_api/l10n/ga.js
new file mode 100644
index 00000000000..6d6b3944c48
--- /dev/null
+++ b/apps/provisioning_api/l10n/ga.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Ní mór gur riarthóir é cuntas logáilte isteach nó údarú a bheith agat an socrú seo a chur in eagar.",
+ "Could not create non-existing user ID" : "Níorbh fhéidir aitheantas úsáideora nach bhfuil ann cheana a chruthú",
+ "User already exists" : "Úsáideoir ann cheana féin",
+ "Group %1$s does not exist" : "Níl grúpa %1$s ann",
+ "Insufficient privileges for group %1$s" : "Pribhléidí neamhleor don ghrúpa %1$s",
+ "No group specified (required for sub-admins)" : "Níor sonraíodh grúpa ar bith (riachtanach le haghaidh fo-riaracháin)",
+ "Sub-admin group does not exist" : "Níl foghrúpa riaracháin ann",
+ "Cannot create sub-admins for admin group" : "Ní féidir fo-riaracháin a chruthú don ghrúpa riaracháin",
+ "No permissions to promote sub-admins" : "Níl aon chead chun fo-riaracháin a chur chun cinn",
+ "Invalid password value" : "Luach pasfhocail neamhbhailí",
+ "An email address is required, to send a password link to the user." : "Tá seoladh ríomhphoist ag teastáil, chun nasc pasfhocal a sheoladh chuig an úsáideoir.",
+ "Required email address was not provided" : "Níor cuireadh an seoladh ríomhphoist riachtanach ar fáil",
+ "User creation failed" : "Theip ar chruthú úsáideora",
+ "Invalid quota value: %1$s" : "Luach cuóta neamhbhailí: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Luach cuóta neamhbhailí. Tá %1$s níos mó ná an t-uaschuóta",
+ "Unlimited quota is forbidden on this instance" : "Tá cosc ​​ar chuóta neamhtheoranta sa chás seo",
+ "Setting the password is not supported by the users backend" : "Ní thacaíonn inneall na n-úsáideoirí leis an bhfocal faire a shocrú",
+ "Invalid language" : "Teanga neamhbhailí",
+ "Invalid locale" : "Logán neamhbhailí",
+ "Invalid first day of week" : "An chéad lá den tseachtain neamhbhailí",
+ "Cannot remove yourself from the admin group" : "Ní féidir tú féin a bhaint den ghrúpa riaracháin",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Ní féidir tú féin a bhaint den ghrúpa seo toisc gur fo-riarthóir tú",
+ "Not viable to remove user from the last group you are sub-admin of" : "Níl sé inmharthana an t-úsáideoir a bhaint den ghrúpa deiridh a bhfuil tú ina fho-riarachán de",
+ "User does not exist" : "Níl an t-úsáideoir ann",
+ "Group does not exist" : "Níl an grúpa ann",
+ "User is not a sub-admin of this group" : "Ní fo-riarthóir den ghrúpa seo é an t-úsáideoir",
+ "Email address not available" : "Níl an seoladh ríomhphoist ar fáil",
+ "Sending email failed" : "Theip ar sheoladh ríomhphoist",
+ "Email confirmation" : "Deimhniú ríomhphoist",
+ "To enable the email address %s please click the button below." : "Chun an seoladh ríomhphoist %s a chumasú cliceáil ar an gcnaipe thíos le do thoil.",
+ "Confirm" : "Deimhnigh",
+ "Email was already removed from account and cannot be confirmed anymore." : "Baineadh an ríomhphost den chuntas cheana agus ní féidir é a dheimhniú a thuilleadh.",
+ "Could not verify mail because the token is expired." : "Níorbh fhéidir ríomhphost a fhíorú toisc go bhfuil an comhartha imithe in éag.",
+ "Could not verify mail because the token is invalid." : "Níorbh fhéidir ríomhphost a fhíorú toisc go bhfuil an comhartha neamhbhailí.",
+ "An unexpected error occurred. Please contact your admin." : "Tharla earráid gan choinne. Déan teagmháil le do riarthóir le do thoil.",
+ "Email confirmation successful" : "D'éirigh le dearbhú ríomhphoist",
+ "Provisioning API" : "Soláthar API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Cumasaíonn an feidhmchlár seo sraith APIanna is féidir le córais sheachtracha a úsáid chun cuntais, grúpaí agus aipeanna a bhainistiú.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Cumasaíonn an feidhmchlár seo sraith APIanna is féidir le córais sheachtracha a úsáid chun cuntas a chruthú, a chur in eagar, a scriosadh agus a cheistiú\n\t\t tréithe, ceistigh, socraigh agus bain grúpaí, socraigh cuóta agus ceistigh an stór iomlán a úsáidtear in Nextcloud. Cuntais riaracháin ghrúpa\n\t\t is féidir Nextcloud a cheistiú freisin agus na feidhmeanna céanna a chomhlíonadh agus a fheidhmíonn riarthóir do ghrúpaí a bhainistíonn siad. Cuireann an API ar chumas freisin\n\t\t admin chun iarratas a dhéanamh maidir le feidhmchláir ghníomhacha Nextcloud, faisnéis feidhmchláir, agus chun aip a chumasú nó a dhíchumasú go cianda.\n\t\t Nuair atá an aip cumasaithe, is féidir iarratais HTTP a úsáid trí cheanntásc Basic Auth chun aon cheann de na feidhmeanna a dhéanamh\n\t\t liostaithe thuas. Tá tuilleadh faisnéise ar fáil i gcáipéisíocht an API Soláthar, lena n-áirítear glaonna mar shampla\n\t\t agus freagraí freastalaí."
+},
+"nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);");
diff --git a/apps/provisioning_api/l10n/ga.json b/apps/provisioning_api/l10n/ga.json
new file mode 100644
index 00000000000..691a2dc7af6
--- /dev/null
+++ b/apps/provisioning_api/l10n/ga.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Ní mór gur riarthóir é cuntas logáilte isteach nó údarú a bheith agat an socrú seo a chur in eagar.",
+ "Could not create non-existing user ID" : "Níorbh fhéidir aitheantas úsáideora nach bhfuil ann cheana a chruthú",
+ "User already exists" : "Úsáideoir ann cheana féin",
+ "Group %1$s does not exist" : "Níl grúpa %1$s ann",
+ "Insufficient privileges for group %1$s" : "Pribhléidí neamhleor don ghrúpa %1$s",
+ "No group specified (required for sub-admins)" : "Níor sonraíodh grúpa ar bith (riachtanach le haghaidh fo-riaracháin)",
+ "Sub-admin group does not exist" : "Níl foghrúpa riaracháin ann",
+ "Cannot create sub-admins for admin group" : "Ní féidir fo-riaracháin a chruthú don ghrúpa riaracháin",
+ "No permissions to promote sub-admins" : "Níl aon chead chun fo-riaracháin a chur chun cinn",
+ "Invalid password value" : "Luach pasfhocail neamhbhailí",
+ "An email address is required, to send a password link to the user." : "Tá seoladh ríomhphoist ag teastáil, chun nasc pasfhocal a sheoladh chuig an úsáideoir.",
+ "Required email address was not provided" : "Níor cuireadh an seoladh ríomhphoist riachtanach ar fáil",
+ "User creation failed" : "Theip ar chruthú úsáideora",
+ "Invalid quota value: %1$s" : "Luach cuóta neamhbhailí: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Luach cuóta neamhbhailí. Tá %1$s níos mó ná an t-uaschuóta",
+ "Unlimited quota is forbidden on this instance" : "Tá cosc ​​ar chuóta neamhtheoranta sa chás seo",
+ "Setting the password is not supported by the users backend" : "Ní thacaíonn inneall na n-úsáideoirí leis an bhfocal faire a shocrú",
+ "Invalid language" : "Teanga neamhbhailí",
+ "Invalid locale" : "Logán neamhbhailí",
+ "Invalid first day of week" : "An chéad lá den tseachtain neamhbhailí",
+ "Cannot remove yourself from the admin group" : "Ní féidir tú féin a bhaint den ghrúpa riaracháin",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Ní féidir tú féin a bhaint den ghrúpa seo toisc gur fo-riarthóir tú",
+ "Not viable to remove user from the last group you are sub-admin of" : "Níl sé inmharthana an t-úsáideoir a bhaint den ghrúpa deiridh a bhfuil tú ina fho-riarachán de",
+ "User does not exist" : "Níl an t-úsáideoir ann",
+ "Group does not exist" : "Níl an grúpa ann",
+ "User is not a sub-admin of this group" : "Ní fo-riarthóir den ghrúpa seo é an t-úsáideoir",
+ "Email address not available" : "Níl an seoladh ríomhphoist ar fáil",
+ "Sending email failed" : "Theip ar sheoladh ríomhphoist",
+ "Email confirmation" : "Deimhniú ríomhphoist",
+ "To enable the email address %s please click the button below." : "Chun an seoladh ríomhphoist %s a chumasú cliceáil ar an gcnaipe thíos le do thoil.",
+ "Confirm" : "Deimhnigh",
+ "Email was already removed from account and cannot be confirmed anymore." : "Baineadh an ríomhphost den chuntas cheana agus ní féidir é a dheimhniú a thuilleadh.",
+ "Could not verify mail because the token is expired." : "Níorbh fhéidir ríomhphost a fhíorú toisc go bhfuil an comhartha imithe in éag.",
+ "Could not verify mail because the token is invalid." : "Níorbh fhéidir ríomhphost a fhíorú toisc go bhfuil an comhartha neamhbhailí.",
+ "An unexpected error occurred. Please contact your admin." : "Tharla earráid gan choinne. Déan teagmháil le do riarthóir le do thoil.",
+ "Email confirmation successful" : "D'éirigh le dearbhú ríomhphoist",
+ "Provisioning API" : "Soláthar API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Cumasaíonn an feidhmchlár seo sraith APIanna is féidir le córais sheachtracha a úsáid chun cuntais, grúpaí agus aipeanna a bhainistiú.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Cumasaíonn an feidhmchlár seo sraith APIanna is féidir le córais sheachtracha a úsáid chun cuntas a chruthú, a chur in eagar, a scriosadh agus a cheistiú\n\t\t tréithe, ceistigh, socraigh agus bain grúpaí, socraigh cuóta agus ceistigh an stór iomlán a úsáidtear in Nextcloud. Cuntais riaracháin ghrúpa\n\t\t is féidir Nextcloud a cheistiú freisin agus na feidhmeanna céanna a chomhlíonadh agus a fheidhmíonn riarthóir do ghrúpaí a bhainistíonn siad. Cuireann an API ar chumas freisin\n\t\t admin chun iarratas a dhéanamh maidir le feidhmchláir ghníomhacha Nextcloud, faisnéis feidhmchláir, agus chun aip a chumasú nó a dhíchumasú go cianda.\n\t\t Nuair atá an aip cumasaithe, is féidir iarratais HTTP a úsáid trí cheanntásc Basic Auth chun aon cheann de na feidhmeanna a dhéanamh\n\t\t liostaithe thuas. Tá tuilleadh faisnéise ar fáil i gcáipéisíocht an API Soláthar, lena n-áirítear glaonna mar shampla\n\t\t agus freagraí freastalaí."
+},"pluralForm" :"nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/gl.js b/apps/provisioning_api/l10n/gl.js
new file mode 100644
index 00000000000..20d47f8b28e
--- /dev/null
+++ b/apps/provisioning_api/l10n/gl.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "A conta que accede debe ser de administración, de subadministración ou ter dereitos especiais para acceder a este axuste",
+ "Could not create non-existing user ID" : "Non foi posíbel crear un ID de usuario inexistente",
+ "User already exists" : "O usuario xa existe",
+ "Group %1$s does not exist" : "O grupo %1$s non existe",
+ "Insufficient privileges for group %1$s" : "O grupo %1$s non ten privilexios abondo",
+ "No group specified (required for sub-admins)" : "Non se especifica ningún grupo (obrigatorio para subadministración)",
+ "Sub-admin group does not exist" : "Non existe o grupo de subadministración",
+ "Cannot create sub-admins for admin group" : "Non é posibel crear postos de subadministración para o grupo de administración",
+ "No permissions to promote sub-admins" : "Non ten permisos para promover a subadministración",
+ "Invalid password value" : "O valor do contrasinal non é correcto",
+ "An email address is required, to send a password link to the user." : "Precisase dun enderezo de correo-e para enviar unha ligazón de contrasinal ao usuario.",
+ "Required email address was not provided" : "Precisase dun enderezo de correo-e mais non foi fornecido",
+ "Invalid quota value: %1$s" : "Valor de cota incorrecto: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "O valor da cota é incorrecto. %1$s excede a cota máxima",
+ "Unlimited quota is forbidden on this instance" : "A cota ilimitada está prohibida nesta instancia",
+ "Setting the password is not supported by the users backend" : "O axuste do contrasinal non está admitido na infraestrutura de usuarios",
+ "Invalid language" : "Idioma non válido",
+ "Invalid locale" : "Configuración rexional incorrecta",
+ "Invalid first day of week" : "O primeiro día da semana non é válido",
+ "Cannot remove yourself from the admin group" : "Non pode retirarse do grupo de administración",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Non pode retirarse deste grupo xa que Vde. é persoal de subadministración",
+ "Not viable to remove user from the last group you are sub-admin of" : "Non é viábel retirar o usuario do último grupo do que é persoal de subadministración",
+ "User does not exist" : "O usuario non existe",
+ "Group does not exist" : "O grupo non existe",
+ "User is not a sub-admin of this group" : "O usuario non pertence á subadministración deste grupo",
+ "Email address not available" : "O enderezo de correo-e non está dispoñíbel",
+ "Sending email failed" : "Produciuse un fallo ao enviar o correo-e",
+ "Email confirmation" : "Confirmación do correo",
+ "To enable the email address %s please click the button below." : "Para activar o enderezo de correo %s, prema no botón de embaixo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "O correo foi retirado da conta e xa non é posíbel confirmalo.",
+ "Could not verify mail because the token is expired." : "Non foi posíbel verificar o correo porque o testemuño caducou.",
+ "Could not verify mail because the token is invalid." : "Non foi posíbel verificar o correo porque o testemuño non é válido.",
+ "An unexpected error occurred. Please contact your admin." : "Produciuse un erro non agardado. Póñase en contacto cun administrador.",
+ "Email confirmation successful" : "Confirmación de correo satisfactoria",
+ "Provisioning API" : "API de aprovisionamento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación activa un conxunto de API que os sistemas externos poden usar para xestionar contas, grupos e aplicacións.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Esta aplicación activa un conxunto de API que os sistemas externos poden usar para crear, editar, eliminar e consultar\n\t\tos atributos da conta, consultar, definir e retirar grupos, definir a cota e consultar o almacenamento total\n\t\tutilizado en Nextcloud. . As contas de administración de grupos tamén poden consultar Nextcloud e realizar as\n\t\tmesmas funcións que a administración da instancia para os grupos que xestionan. A API tamén permite á administración\n\t\tconsultar aplicacións activas de Nextcloud, información da aplicación e activar ou desactivar unha aplicación remotamente.\n\t\tUnha vez que a aplicación estea activada, as solicitudes HTTP pódense usar a través dunha cabeceira de autenticación básica (Basic Auth) para\n\t\trealizar calquera das funcións listadas anteriormente. Hai dispoñíbel máis información na documentación da API \n\t\tde aprovisionamento, incluíndo exemplos de chamadas e respostas do servidor."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/gl.json b/apps/provisioning_api/l10n/gl.json
new file mode 100644
index 00000000000..59dbb4af966
--- /dev/null
+++ b/apps/provisioning_api/l10n/gl.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "A conta que accede debe ser de administración, de subadministración ou ter dereitos especiais para acceder a este axuste",
+ "Could not create non-existing user ID" : "Non foi posíbel crear un ID de usuario inexistente",
+ "User already exists" : "O usuario xa existe",
+ "Group %1$s does not exist" : "O grupo %1$s non existe",
+ "Insufficient privileges for group %1$s" : "O grupo %1$s non ten privilexios abondo",
+ "No group specified (required for sub-admins)" : "Non se especifica ningún grupo (obrigatorio para subadministración)",
+ "Sub-admin group does not exist" : "Non existe o grupo de subadministración",
+ "Cannot create sub-admins for admin group" : "Non é posibel crear postos de subadministración para o grupo de administración",
+ "No permissions to promote sub-admins" : "Non ten permisos para promover a subadministración",
+ "Invalid password value" : "O valor do contrasinal non é correcto",
+ "An email address is required, to send a password link to the user." : "Precisase dun enderezo de correo-e para enviar unha ligazón de contrasinal ao usuario.",
+ "Required email address was not provided" : "Precisase dun enderezo de correo-e mais non foi fornecido",
+ "Invalid quota value: %1$s" : "Valor de cota incorrecto: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "O valor da cota é incorrecto. %1$s excede a cota máxima",
+ "Unlimited quota is forbidden on this instance" : "A cota ilimitada está prohibida nesta instancia",
+ "Setting the password is not supported by the users backend" : "O axuste do contrasinal non está admitido na infraestrutura de usuarios",
+ "Invalid language" : "Idioma non válido",
+ "Invalid locale" : "Configuración rexional incorrecta",
+ "Invalid first day of week" : "O primeiro día da semana non é válido",
+ "Cannot remove yourself from the admin group" : "Non pode retirarse do grupo de administración",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Non pode retirarse deste grupo xa que Vde. é persoal de subadministración",
+ "Not viable to remove user from the last group you are sub-admin of" : "Non é viábel retirar o usuario do último grupo do que é persoal de subadministración",
+ "User does not exist" : "O usuario non existe",
+ "Group does not exist" : "O grupo non existe",
+ "User is not a sub-admin of this group" : "O usuario non pertence á subadministración deste grupo",
+ "Email address not available" : "O enderezo de correo-e non está dispoñíbel",
+ "Sending email failed" : "Produciuse un fallo ao enviar o correo-e",
+ "Email confirmation" : "Confirmación do correo",
+ "To enable the email address %s please click the button below." : "Para activar o enderezo de correo %s, prema no botón de embaixo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "O correo foi retirado da conta e xa non é posíbel confirmalo.",
+ "Could not verify mail because the token is expired." : "Non foi posíbel verificar o correo porque o testemuño caducou.",
+ "Could not verify mail because the token is invalid." : "Non foi posíbel verificar o correo porque o testemuño non é válido.",
+ "An unexpected error occurred. Please contact your admin." : "Produciuse un erro non agardado. Póñase en contacto cun administrador.",
+ "Email confirmation successful" : "Confirmación de correo satisfactoria",
+ "Provisioning API" : "API de aprovisionamento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Esta aplicación activa un conxunto de API que os sistemas externos poden usar para xestionar contas, grupos e aplicacións.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Esta aplicación activa un conxunto de API que os sistemas externos poden usar para crear, editar, eliminar e consultar\n\t\tos atributos da conta, consultar, definir e retirar grupos, definir a cota e consultar o almacenamento total\n\t\tutilizado en Nextcloud. . As contas de administración de grupos tamén poden consultar Nextcloud e realizar as\n\t\tmesmas funcións que a administración da instancia para os grupos que xestionan. A API tamén permite á administración\n\t\tconsultar aplicacións activas de Nextcloud, información da aplicación e activar ou desactivar unha aplicación remotamente.\n\t\tUnha vez que a aplicación estea activada, as solicitudes HTTP pódense usar a través dunha cabeceira de autenticación básica (Basic Auth) para\n\t\trealizar calquera das funcións listadas anteriormente. Hai dispoñíbel máis información na documentación da API \n\t\tde aprovisionamento, incluíndo exemplos de chamadas e respostas do servidor."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/ja.js b/apps/provisioning_api/l10n/ja.js
new file mode 100644
index 00000000000..b4775480591
--- /dev/null
+++ b/apps/provisioning_api/l10n/ja.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "ログインアカウントは管理者であるか、この設定を編集する権限を持っている必要があります。",
+ "Could not create non-existing user ID" : "存在しないユーザIDを作成できませんでした",
+ "User already exists" : "ユーザは既に存在する",
+ "Group %1$s does not exist" : "グループ %1$s は存在しません",
+ "Insufficient privileges for group %1$s" : "グループ %1$s の権限が不十分です",
+ "No group specified (required for sub-admins)" : "グループが指定されていません(サブ管理者に必要です)",
+ "Sub-admin group does not exist" : "サブ管理者グループは存在しません",
+ "Cannot create sub-admins for admin group" : "管理者グループにサブ管理者を作成することはできません",
+ "No permissions to promote sub-admins" : "権限がないため、サブ管理者を昇格させることはできません",
+ "Invalid password value" : "無効なパスワード値",
+ "An email address is required, to send a password link to the user." : "ユーザーにパスワードリンクを送信するため、メールアドレスが必要です。",
+ "Required email address was not provided" : "必要のEメールアドレスが提供されていません",
+ "User creation failed" : "ユーザーの作成に失敗しました",
+ "Invalid quota value: %1$s" : "無効なクォータ値: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "無効なクォータ値。%1$sは最大クォータを超えています",
+ "Unlimited quota is forbidden on this instance" : "このインスタンスでは無制限のクォータは禁止されています。",
+ "Setting the password is not supported by the users backend" : "パスワードの設定は、ユーザ・バックエンドではサポートされていません",
+ "Invalid language" : "無効な言語",
+ "Invalid locale" : "無効なロケール",
+ "Invalid first day of week" : "無効な週の最初の曜日",
+ "Cannot remove yourself from the admin group" : "管理者グループから自分自身を削除することはできません",
+ "Cannot remove yourself from this group as you are a sub-admin" : "あなたはサブ管理者であるため、このグループから自分を削除することはできません",
+ "Not viable to remove user from the last group you are sub-admin of" : "あなたがサブ管理者である最後のグループからユーザを削除することはできません",
+ "User does not exist" : "ユーザは存在しません",
+ "Group does not exist" : "グループは存在しません",
+ "User is not a sub-admin of this group" : "ユーザはこのグループのサブ管理者ではありません。",
+ "Email address not available" : "Eメールアドレスは利用できません",
+ "Sending email failed" : "Eメールの送信に失敗しました",
+ "Email confirmation" : "Eメールの確認",
+ "To enable the email address %s please click the button below." : "メールアドレス %s を有効にするには、下のボタンをクリックしてください。",
+ "Confirm" : "承認",
+ "Email was already removed from account and cannot be confirmed anymore." : "メールアドレスはすでにアカウントから削除されており、確認できません。",
+ "Could not verify mail because the token is expired." : "トークンの有効期限が切れているため、メールを検証できませんでした。",
+ "Could not verify mail because the token is invalid." : "トークンが無効なため、メールを検証できませんでした。",
+ "An unexpected error occurred. Please contact your admin." : "予期せぬエラーが発生しました。管理者に連絡してください。",
+ "Email confirmation successful" : "Eメールの確認が成功しました",
+ "Provisioning API" : "プロビジョニングAPI",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "このアプリケーションは、外部システムがアカウント、グループ、アプリを管理するために使用できる一連のAPIを有効にします。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "このアプリケーションは、外部システムがNextcloudでアカウント属性を作成、編集、削除、クエリしたり、\n\t\tグループをクエリしたり、設定したり、削除したり、クォータを設定したり、使用されている総ストレージを\n\t\tクエリしたりするために使用できる一連のAPIを有効にします。グループ管理アカウントは、管理している\n\t\tグループに対して管理者と同じ機能を実行することができるだけでなく、Nextcloudをクエリすることもできます。\n\t\tこのAPIはまた、管理者がアクティブなNextcloudアプリケーションやアプリケーション情報をクエリし、アプリを\n\t\tリモートで有効または無効にすることも可能にします。アプリが有効になると、上記にリストされている機能を\n\t\t実行するために、Basic Authヘッダーを介したHTTPリクエストを使用することができます。詳細な情報や\n\t\tサンプルの呼び出し、サーバーからの応答などは、Provisioning APIのドキュメントで確認できます。"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/provisioning_api/l10n/ja.json b/apps/provisioning_api/l10n/ja.json
new file mode 100644
index 00000000000..8b057bdbaa1
--- /dev/null
+++ b/apps/provisioning_api/l10n/ja.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "ログインアカウントは管理者であるか、この設定を編集する権限を持っている必要があります。",
+ "Could not create non-existing user ID" : "存在しないユーザIDを作成できませんでした",
+ "User already exists" : "ユーザは既に存在する",
+ "Group %1$s does not exist" : "グループ %1$s は存在しません",
+ "Insufficient privileges for group %1$s" : "グループ %1$s の権限が不十分です",
+ "No group specified (required for sub-admins)" : "グループが指定されていません(サブ管理者に必要です)",
+ "Sub-admin group does not exist" : "サブ管理者グループは存在しません",
+ "Cannot create sub-admins for admin group" : "管理者グループにサブ管理者を作成することはできません",
+ "No permissions to promote sub-admins" : "権限がないため、サブ管理者を昇格させることはできません",
+ "Invalid password value" : "無効なパスワード値",
+ "An email address is required, to send a password link to the user." : "ユーザーにパスワードリンクを送信するため、メールアドレスが必要です。",
+ "Required email address was not provided" : "必要のEメールアドレスが提供されていません",
+ "User creation failed" : "ユーザーの作成に失敗しました",
+ "Invalid quota value: %1$s" : "無効なクォータ値: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "無効なクォータ値。%1$sは最大クォータを超えています",
+ "Unlimited quota is forbidden on this instance" : "このインスタンスでは無制限のクォータは禁止されています。",
+ "Setting the password is not supported by the users backend" : "パスワードの設定は、ユーザ・バックエンドではサポートされていません",
+ "Invalid language" : "無効な言語",
+ "Invalid locale" : "無効なロケール",
+ "Invalid first day of week" : "無効な週の最初の曜日",
+ "Cannot remove yourself from the admin group" : "管理者グループから自分自身を削除することはできません",
+ "Cannot remove yourself from this group as you are a sub-admin" : "あなたはサブ管理者であるため、このグループから自分を削除することはできません",
+ "Not viable to remove user from the last group you are sub-admin of" : "あなたがサブ管理者である最後のグループからユーザを削除することはできません",
+ "User does not exist" : "ユーザは存在しません",
+ "Group does not exist" : "グループは存在しません",
+ "User is not a sub-admin of this group" : "ユーザはこのグループのサブ管理者ではありません。",
+ "Email address not available" : "Eメールアドレスは利用できません",
+ "Sending email failed" : "Eメールの送信に失敗しました",
+ "Email confirmation" : "Eメールの確認",
+ "To enable the email address %s please click the button below." : "メールアドレス %s を有効にするには、下のボタンをクリックしてください。",
+ "Confirm" : "承認",
+ "Email was already removed from account and cannot be confirmed anymore." : "メールアドレスはすでにアカウントから削除されており、確認できません。",
+ "Could not verify mail because the token is expired." : "トークンの有効期限が切れているため、メールを検証できませんでした。",
+ "Could not verify mail because the token is invalid." : "トークンが無効なため、メールを検証できませんでした。",
+ "An unexpected error occurred. Please contact your admin." : "予期せぬエラーが発生しました。管理者に連絡してください。",
+ "Email confirmation successful" : "Eメールの確認が成功しました",
+ "Provisioning API" : "プロビジョニングAPI",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "このアプリケーションは、外部システムがアカウント、グループ、アプリを管理するために使用できる一連のAPIを有効にします。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "このアプリケーションは、外部システムがNextcloudでアカウント属性を作成、編集、削除、クエリしたり、\n\t\tグループをクエリしたり、設定したり、削除したり、クォータを設定したり、使用されている総ストレージを\n\t\tクエリしたりするために使用できる一連のAPIを有効にします。グループ管理アカウントは、管理している\n\t\tグループに対して管理者と同じ機能を実行することができるだけでなく、Nextcloudをクエリすることもできます。\n\t\tこのAPIはまた、管理者がアクティブなNextcloudアプリケーションやアプリケーション情報をクエリし、アプリを\n\t\tリモートで有効または無効にすることも可能にします。アプリが有効になると、上記にリストされている機能を\n\t\t実行するために、Basic Authヘッダーを介したHTTPリクエストを使用することができます。詳細な情報や\n\t\tサンプルの呼び出し、サーバーからの応答などは、Provisioning APIのドキュメントで確認できます。"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/nb.js b/apps/provisioning_api/l10n/nb.js
new file mode 100644
index 00000000000..b20e422af1b
--- /dev/null
+++ b/apps/provisioning_api/l10n/nb.js
@@ -0,0 +1,42 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Pålogget konto må være administrator eller ha autorisasjon til å redigere denne innstillingen.",
+ "Could not create non-existing user ID" : "Kunne ikke opprette ikke-eksisterende bruker-ID",
+ "User already exists" : "Brukeren eksisterer allerede",
+ "Group %1$s does not exist" : "Gruppe %1$s finnes ikke",
+ "Insufficient privileges for group %1$s" : "Utilstrekkelige privilegier for gruppe %1$s",
+ "No group specified (required for sub-admins)" : "Ingen gruppe spesifisert (kreves for underadministratorer)",
+ "Sub-admin group does not exist" : "Underadministratorgruppe finnes ikke",
+ "Cannot create sub-admins for admin group" : "Kan ikke opprette underadministratorer for admingruppe",
+ "No permissions to promote sub-admins" : "Ingen tillatelser til å forfremme underadministratorer",
+ "Invalid password value" : "Ugyldig passordverdi",
+ "Required email address was not provided" : "Nødvendig e-postadresse ble ikke oppgitt",
+ "Invalid quota value: %1$s" : "Ugyldig kvoteverdi: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ugyldig kvoteverdi. %1$s overskrider den maksimale kvoten",
+ "Unlimited quota is forbidden on this instance" : "Ubegrenset kvote er forbudt på denne forekomsten",
+ "Setting the password is not supported by the users backend" : "Innstilling av passordet støttes ikke av brukerens backend",
+ "Invalid language" : "Ugyldig språk",
+ "Invalid locale" : "Ugyldig nasjonal innstilling",
+ "Invalid first day of week" : "Ugyldig første dag i uken",
+ "Cannot remove yourself from the admin group" : "Kan ikke fjerne deg selv fra administratorgruppen",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Kan ikke fjerne deg selv fra denne gruppen da du er en underadministrator",
+ "Not viable to remove user from the last group you are sub-admin of" : "Ikke mulig å fjerne brukeren fra den siste gruppen du er underadministrator for",
+ "User does not exist" : "Brukeren finnes ikke",
+ "Group does not exist" : "Gruppen finnes ikke",
+ "User is not a sub-admin of this group" : "Brukeren er ikke en underadministrator for denne gruppen",
+ "Email address not available" : "E-postadresse ikke tilgjengelig",
+ "Sending email failed" : "Sending av e-post feilet",
+ "Email confirmation" : "E-postbekreftelse",
+ "To enable the email address %s please click the button below." : "Klikk på knappen nedenfor for å aktivere e-postadressen %s.",
+ "Confirm" : "Bekreft",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-posten er allerede fjernet fra kontoen og kan ikke bekreftes lenger.",
+ "Could not verify mail because the token is expired." : "Kunne ikke bekrefte e-posten fordi nøkkelen er utløpt.",
+ "Could not verify mail because the token is invalid." : "Kunne ikke bekrefte e-post fordi nøkkelen er ugyldig.",
+ "An unexpected error occurred. Please contact your admin." : "En uventet feil oppsto. Ta kontakt med administratoren din.",
+ "Email confirmation successful" : "E-postbekreftelse vellykket",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Denne applikasjonen aktiverer et sett med API-er som eksterne systemer kan bruke til å administrere kontoer, grupper og apper.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Denne applikasjonen aktiverer et sett med APIer som eksterne systemer kan bruke til å opprette, redigere, slette og spørre konto\n\t\tattributter, spørring, angi og fjern grupper, angi kvote og spørring total lagring brukt i Nextcloud. Kontoer for gruppeadministrator\n\t\tkan også spørre Nextcloud og utføre de samme funksjonene som en administrator for grupper de administrerer. API-en muliggjør også\n\t\ten administrator for å spørre etter aktive Nextcloud-applikasjoner, applikasjonsinformasjon og for å aktivere eller deaktivere en app eksternt.\n\t\tNår appen er aktivert, kan HTTP-forespørsler brukes via en Basic Auth-header for å utføre noen av funksjonene\n\t\tlistet ovenfor. Du finner mer informasjon i dokumentasjonen for Provisioning API, inkludert eksempelkall\n\t\tog serversvar."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/nb.json b/apps/provisioning_api/l10n/nb.json
new file mode 100644
index 00000000000..19d92e4ba26
--- /dev/null
+++ b/apps/provisioning_api/l10n/nb.json
@@ -0,0 +1,40 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Pålogget konto må være administrator eller ha autorisasjon til å redigere denne innstillingen.",
+ "Could not create non-existing user ID" : "Kunne ikke opprette ikke-eksisterende bruker-ID",
+ "User already exists" : "Brukeren eksisterer allerede",
+ "Group %1$s does not exist" : "Gruppe %1$s finnes ikke",
+ "Insufficient privileges for group %1$s" : "Utilstrekkelige privilegier for gruppe %1$s",
+ "No group specified (required for sub-admins)" : "Ingen gruppe spesifisert (kreves for underadministratorer)",
+ "Sub-admin group does not exist" : "Underadministratorgruppe finnes ikke",
+ "Cannot create sub-admins for admin group" : "Kan ikke opprette underadministratorer for admingruppe",
+ "No permissions to promote sub-admins" : "Ingen tillatelser til å forfremme underadministratorer",
+ "Invalid password value" : "Ugyldig passordverdi",
+ "Required email address was not provided" : "Nødvendig e-postadresse ble ikke oppgitt",
+ "Invalid quota value: %1$s" : "Ugyldig kvoteverdi: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Ugyldig kvoteverdi. %1$s overskrider den maksimale kvoten",
+ "Unlimited quota is forbidden on this instance" : "Ubegrenset kvote er forbudt på denne forekomsten",
+ "Setting the password is not supported by the users backend" : "Innstilling av passordet støttes ikke av brukerens backend",
+ "Invalid language" : "Ugyldig språk",
+ "Invalid locale" : "Ugyldig nasjonal innstilling",
+ "Invalid first day of week" : "Ugyldig første dag i uken",
+ "Cannot remove yourself from the admin group" : "Kan ikke fjerne deg selv fra administratorgruppen",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Kan ikke fjerne deg selv fra denne gruppen da du er en underadministrator",
+ "Not viable to remove user from the last group you are sub-admin of" : "Ikke mulig å fjerne brukeren fra den siste gruppen du er underadministrator for",
+ "User does not exist" : "Brukeren finnes ikke",
+ "Group does not exist" : "Gruppen finnes ikke",
+ "User is not a sub-admin of this group" : "Brukeren er ikke en underadministrator for denne gruppen",
+ "Email address not available" : "E-postadresse ikke tilgjengelig",
+ "Sending email failed" : "Sending av e-post feilet",
+ "Email confirmation" : "E-postbekreftelse",
+ "To enable the email address %s please click the button below." : "Klikk på knappen nedenfor for å aktivere e-postadressen %s.",
+ "Confirm" : "Bekreft",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-posten er allerede fjernet fra kontoen og kan ikke bekreftes lenger.",
+ "Could not verify mail because the token is expired." : "Kunne ikke bekrefte e-posten fordi nøkkelen er utløpt.",
+ "Could not verify mail because the token is invalid." : "Kunne ikke bekrefte e-post fordi nøkkelen er ugyldig.",
+ "An unexpected error occurred. Please contact your admin." : "En uventet feil oppsto. Ta kontakt med administratoren din.",
+ "Email confirmation successful" : "E-postbekreftelse vellykket",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Denne applikasjonen aktiverer et sett med API-er som eksterne systemer kan bruke til å administrere kontoer, grupper og apper.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Denne applikasjonen aktiverer et sett med APIer som eksterne systemer kan bruke til å opprette, redigere, slette og spørre konto\n\t\tattributter, spørring, angi og fjern grupper, angi kvote og spørring total lagring brukt i Nextcloud. Kontoer for gruppeadministrator\n\t\tkan også spørre Nextcloud og utføre de samme funksjonene som en administrator for grupper de administrerer. API-en muliggjør også\n\t\ten administrator for å spørre etter aktive Nextcloud-applikasjoner, applikasjonsinformasjon og for å aktivere eller deaktivere en app eksternt.\n\t\tNår appen er aktivert, kan HTTP-forespørsler brukes via en Basic Auth-header for å utføre noen av funksjonene\n\t\tlistet ovenfor. Du finner mer informasjon i dokumentasjonen for Provisioning API, inkludert eksempelkall\n\t\tog serversvar."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/pl.js b/apps/provisioning_api/l10n/pl.js
new file mode 100644
index 00000000000..b477b89f024
--- /dev/null
+++ b/apps/provisioning_api/l10n/pl.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Zalogowane konto musi być administratorem lub mieć uprawnienia do edycji tego ustawienia.",
+ "Could not create non-existing user ID" : "Nie można utworzyć nieistniejącego identyfikatora użytkownika",
+ "User already exists" : "Użytkownik już istnieje",
+ "Group %1$s does not exist" : "Grupa %1$s nie istnieje",
+ "Insufficient privileges for group %1$s" : "Niewystarczające uprawnienia do grupy %1$s",
+ "No group specified (required for sub-admins)" : "Nie określono grupy (wymagane dla podadministratorów)",
+ "Sub-admin group does not exist" : "Grupa podadministratorów nie istnieje",
+ "Cannot create sub-admins for admin group" : "Nie można tworzyć podadministratorów dla grupy administratorów",
+ "No permissions to promote sub-admins" : "Brak uprawnień do promowania podadministratorów",
+ "Invalid password value" : "Nieprawidłowa wartość hasła",
+ "An email address is required, to send a password link to the user." : "Wymagany jest adres e-mail, aby wysłać użytkownikowi link do ustawienia hasła.",
+ "Required email address was not provided" : "Nie podano wymaganego adresu e-mail",
+ "User creation failed" : "Nie udało się utworzyć użytkownika",
+ "Invalid quota value: %1$s" : "Nieprawidłowa wartość limitu: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Nieprawidłowy limit. %1$s przekracza maksymalny dopuszczalny limit",
+ "Unlimited quota is forbidden on this instance" : "Nieograniczony limit jest zabroniony na tej instancji",
+ "Setting the password is not supported by the users backend" : "Ustawianie hasła nie jest obsługiwane przez backend użytkowników",
+ "Invalid language" : "Nieprawidłowy język",
+ "Invalid locale" : "Nieprawidłowa lokalizacja",
+ "Invalid first day of week" : "Nieprawidłowy pierwszy dzień tygodnia",
+ "Cannot remove yourself from the admin group" : "Nie możesz usunąć siebie z grupy administratorów",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Nie możesz usunąć siebie z tej grupy, ponieważ jesteś jej podadministratorem",
+ "Not viable to remove user from the last group you are sub-admin of" : "Nie można usunąć użytkownika z ostatniej grupy, której jest podadministratorem",
+ "User does not exist" : "Użytkownik nie istnieje",
+ "Group does not exist" : "Grupa nie istnieje",
+ "User is not a sub-admin of this group" : "Użytkownik nie jest podadministratorem tej grupy",
+ "Email address not available" : "Adres e-mail niedostępny",
+ "Sending email failed" : "Wysyłanie e-maila nie powiodło się",
+ "Email confirmation" : "Potwierdzenie e-mailem",
+ "To enable the email address %s please click the button below." : "Aby włączyć adres e-mail %s, kliknij poniższy przycisk.",
+ "Confirm" : "Potwierdź",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mail został już usunięty z konta i nie można go już potwierdzić.",
+ "Could not verify mail because the token is expired." : "Nie można zweryfikować poczty, ponieważ token wygasł.",
+ "Could not verify mail because the token is invalid." : "Nie można zweryfikować poczty, ponieważ token jest nieprawidłowy.",
+ "An unexpected error occurred. Please contact your admin." : "Wystąpił nieoczekiwany błąd. Skontaktuj się z administratorem.",
+ "Email confirmation successful" : "Potwierdzenie e-maila powiodło się",
+ "Provisioning API" : "API obsługi administracyjnej",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Ta aplikacja umożliwia zestaw interfejsów API, które zewnętrzne systemy mogą wykorzystać do zarządzania kontami, grupami i aplikacjami.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Ta aplikacja udostępnia zestaw interfejsów API, które zewnętrzne systemy mogą wykorzystać do tworzenia, edytowania, usuwania i wyszukiwania kont użytkowników,\n\t\tatrybutów, zapytań, ustawiania i usuwania grup, limitów oraz zapytań o całkowite wykorzystanie przestrzeni w Nextcloud. Konta administratorów grup\n\t\tmogą również wykonywać zapytania do Nextcloud i działać jak administrator dla grup, którymi zarządzają. API umożliwia też administratorowi pobieranie aktywnych aplikacji, ich identyfikatorów, oraz włączanie lub wyłączanie aplikacji zdalnie.\n\t\tPo włączeniu aplikacji, zapytania HTTP mogą być wykonywane z nagłówkiem uwierzytelniającym Basic Auth, aby korzystać z funkcji\n\t\twymienionych powyżej. Więcej informacji znajduje się w dokumentacji API Provisioning, w tym przykładowe wywołania\n\t\ti odpowiedzi serwera."
+},
+"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);");
diff --git a/apps/provisioning_api/l10n/pl.json b/apps/provisioning_api/l10n/pl.json
new file mode 100644
index 00000000000..90e8767ebdd
--- /dev/null
+++ b/apps/provisioning_api/l10n/pl.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Zalogowane konto musi być administratorem lub mieć uprawnienia do edycji tego ustawienia.",
+ "Could not create non-existing user ID" : "Nie można utworzyć nieistniejącego identyfikatora użytkownika",
+ "User already exists" : "Użytkownik już istnieje",
+ "Group %1$s does not exist" : "Grupa %1$s nie istnieje",
+ "Insufficient privileges for group %1$s" : "Niewystarczające uprawnienia do grupy %1$s",
+ "No group specified (required for sub-admins)" : "Nie określono grupy (wymagane dla podadministratorów)",
+ "Sub-admin group does not exist" : "Grupa podadministratorów nie istnieje",
+ "Cannot create sub-admins for admin group" : "Nie można tworzyć podadministratorów dla grupy administratorów",
+ "No permissions to promote sub-admins" : "Brak uprawnień do promowania podadministratorów",
+ "Invalid password value" : "Nieprawidłowa wartość hasła",
+ "An email address is required, to send a password link to the user." : "Wymagany jest adres e-mail, aby wysłać użytkownikowi link do ustawienia hasła.",
+ "Required email address was not provided" : "Nie podano wymaganego adresu e-mail",
+ "User creation failed" : "Nie udało się utworzyć użytkownika",
+ "Invalid quota value: %1$s" : "Nieprawidłowa wartość limitu: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Nieprawidłowy limit. %1$s przekracza maksymalny dopuszczalny limit",
+ "Unlimited quota is forbidden on this instance" : "Nieograniczony limit jest zabroniony na tej instancji",
+ "Setting the password is not supported by the users backend" : "Ustawianie hasła nie jest obsługiwane przez backend użytkowników",
+ "Invalid language" : "Nieprawidłowy język",
+ "Invalid locale" : "Nieprawidłowa lokalizacja",
+ "Invalid first day of week" : "Nieprawidłowy pierwszy dzień tygodnia",
+ "Cannot remove yourself from the admin group" : "Nie możesz usunąć siebie z grupy administratorów",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Nie możesz usunąć siebie z tej grupy, ponieważ jesteś jej podadministratorem",
+ "Not viable to remove user from the last group you are sub-admin of" : "Nie można usunąć użytkownika z ostatniej grupy, której jest podadministratorem",
+ "User does not exist" : "Użytkownik nie istnieje",
+ "Group does not exist" : "Grupa nie istnieje",
+ "User is not a sub-admin of this group" : "Użytkownik nie jest podadministratorem tej grupy",
+ "Email address not available" : "Adres e-mail niedostępny",
+ "Sending email failed" : "Wysyłanie e-maila nie powiodło się",
+ "Email confirmation" : "Potwierdzenie e-mailem",
+ "To enable the email address %s please click the button below." : "Aby włączyć adres e-mail %s, kliknij poniższy przycisk.",
+ "Confirm" : "Potwierdź",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mail został już usunięty z konta i nie można go już potwierdzić.",
+ "Could not verify mail because the token is expired." : "Nie można zweryfikować poczty, ponieważ token wygasł.",
+ "Could not verify mail because the token is invalid." : "Nie można zweryfikować poczty, ponieważ token jest nieprawidłowy.",
+ "An unexpected error occurred. Please contact your admin." : "Wystąpił nieoczekiwany błąd. Skontaktuj się z administratorem.",
+ "Email confirmation successful" : "Potwierdzenie e-maila powiodło się",
+ "Provisioning API" : "API obsługi administracyjnej",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Ta aplikacja umożliwia zestaw interfejsów API, które zewnętrzne systemy mogą wykorzystać do zarządzania kontami, grupami i aplikacjami.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Ta aplikacja udostępnia zestaw interfejsów API, które zewnętrzne systemy mogą wykorzystać do tworzenia, edytowania, usuwania i wyszukiwania kont użytkowników,\n\t\tatrybutów, zapytań, ustawiania i usuwania grup, limitów oraz zapytań o całkowite wykorzystanie przestrzeni w Nextcloud. Konta administratorów grup\n\t\tmogą również wykonywać zapytania do Nextcloud i działać jak administrator dla grup, którymi zarządzają. API umożliwia też administratorowi pobieranie aktywnych aplikacji, ich identyfikatorów, oraz włączanie lub wyłączanie aplikacji zdalnie.\n\t\tPo włączeniu aplikacji, zapytania HTTP mogą być wykonywane z nagłówkiem uwierzytelniającym Basic Auth, aby korzystać z funkcji\n\t\twymienionych powyżej. Więcej informacji znajduje się w dokumentacji API Provisioning, w tym przykładowe wywołania\n\t\ti odpowiedzi serwera."
+},"pluralForm" :"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/pt_BR.js b/apps/provisioning_api/l10n/pt_BR.js
new file mode 100644
index 00000000000..4fbd4024484
--- /dev/null
+++ b/apps/provisioning_api/l10n/pt_BR.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "A conta logada deve ser um administrador ou ter autorização para editar esta configuração.",
+ "Could not create non-existing user ID" : "Não foi possível criar um ID de usuário inexistente",
+ "User already exists" : "Usuário já existe",
+ "Group %1$s does not exist" : "O grupo %1$s não existe",
+ "Insufficient privileges for group %1$s" : "Privilégios insuficientes para o grupo %1$s",
+ "No group specified (required for sub-admins)" : "Nenhum grupo especificado (obrigatório para subadministradores)",
+ "Sub-admin group does not exist" : "O grupo de subadministradores não existe",
+ "Cannot create sub-admins for admin group" : "Não é possível criar subadministradores para o grupo de administradores",
+ "No permissions to promote sub-admins" : "Sem permissões para promover subadministradores",
+ "Invalid password value" : "Valor de senha inválido",
+ "An email address is required, to send a password link to the user." : "É necessário um endereço de e-mail, para enviar um link de senha para o usuário.",
+ "Required email address was not provided" : "O endereço de e-mail obrigatório não foi fornecido",
+ "User creation failed" : "Falha na criação do usuário",
+ "Invalid quota value: %1$s" : "Valor de cota inválido: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valor de cota inválido. %1$s está excedendo a cota máxima",
+ "Unlimited quota is forbidden on this instance" : "Cota ilimitada é proibida nesta instância",
+ "Setting the password is not supported by the users backend" : "A configuração da senha não é suportada pelo back-end dos usuários",
+ "Invalid language" : "Idioma inválido",
+ "Invalid locale" : "Configuração regional inválida",
+ "Invalid first day of week" : "Primeiro dia da semana inválido",
+ "Cannot remove yourself from the admin group" : "Não é possível remover a si mesmo do grupo de administradores",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Não é possível remover a si mesmo desse grupo, pois você é um subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "Não é viável remover o usuário do último grupo do qual você é subadministrador",
+ "User does not exist" : "Usuário não existe",
+ "Group does not exist" : "Grupo não existe",
+ "User is not a sub-admin of this group" : "O usuário não é um subadministrador deste grupo",
+ "Email address not available" : "Endereço de e-mail não disponível",
+ "Sending email failed" : "Falha ao enviar e-mail",
+ "Email confirmation" : "Confirmação do endereço de e-mail",
+ "To enable the email address %s please click the button below." : "Para ativar o endereço de e-mail %s, por favor, clique no botão abaixo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "O e-mail já foi removido da conta e não pode mais ser confirmado.",
+ "Could not verify mail because the token is expired." : "Não foi possível verificar o e-mail porque o token expirou.",
+ "Could not verify mail because the token is invalid." : "Não foi possível verificar o e-mail porque o token é inválido.",
+ "An unexpected error occurred. Please contact your admin." : "Um erro inesperado ocorreu. Entre em contato com o seu administrador.",
+ "Email confirmation successful" : "E-mail confirmado com sucesso",
+ "Provisioning API" : "API de provisionamento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Este aplicativo habilita um conjunto de APIs que sistemas externos podem usar para gerenciar contas, grupos e aplicativos.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Este aplicativo habilita um conjunto de APIs que sistemas externos podem usar para criar, editar, excluir e consultar atributos\n\t\tde conta, consultar, definir e remover grupos, definir cotas e consultar o armazenamento total usado no Nextcloud. As contas de administrador de grupo\n\t\ttambém podem consultar o Nextcloud e executar as mesmas funções de um administrador para os grupos que gerenciam. A API também permite\n\t\tque um administrador consulte os aplicativos ativos do Nextcloud, as informações do aplicativo e ative ou desative um aplicativo remotamente.\n\t\tDepois que o aplicativo é ativado, as solicitações HTTP podem ser usadas por meio de um cabeçalho Basic Auth para executar qualquer uma das funções\n\t\tlistadas acima. Mais informações estão disponíveis na documentação da API de Provisionamento, incluindo exemplos de solicitações\n\t\te respostas do servidor."
+},
+"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/provisioning_api/l10n/pt_BR.json b/apps/provisioning_api/l10n/pt_BR.json
new file mode 100644
index 00000000000..bb951174d30
--- /dev/null
+++ b/apps/provisioning_api/l10n/pt_BR.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "A conta logada deve ser um administrador ou ter autorização para editar esta configuração.",
+ "Could not create non-existing user ID" : "Não foi possível criar um ID de usuário inexistente",
+ "User already exists" : "Usuário já existe",
+ "Group %1$s does not exist" : "O grupo %1$s não existe",
+ "Insufficient privileges for group %1$s" : "Privilégios insuficientes para o grupo %1$s",
+ "No group specified (required for sub-admins)" : "Nenhum grupo especificado (obrigatório para subadministradores)",
+ "Sub-admin group does not exist" : "O grupo de subadministradores não existe",
+ "Cannot create sub-admins for admin group" : "Não é possível criar subadministradores para o grupo de administradores",
+ "No permissions to promote sub-admins" : "Sem permissões para promover subadministradores",
+ "Invalid password value" : "Valor de senha inválido",
+ "An email address is required, to send a password link to the user." : "É necessário um endereço de e-mail, para enviar um link de senha para o usuário.",
+ "Required email address was not provided" : "O endereço de e-mail obrigatório não foi fornecido",
+ "User creation failed" : "Falha na criação do usuário",
+ "Invalid quota value: %1$s" : "Valor de cota inválido: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Valor de cota inválido. %1$s está excedendo a cota máxima",
+ "Unlimited quota is forbidden on this instance" : "Cota ilimitada é proibida nesta instância",
+ "Setting the password is not supported by the users backend" : "A configuração da senha não é suportada pelo back-end dos usuários",
+ "Invalid language" : "Idioma inválido",
+ "Invalid locale" : "Configuração regional inválida",
+ "Invalid first day of week" : "Primeiro dia da semana inválido",
+ "Cannot remove yourself from the admin group" : "Não é possível remover a si mesmo do grupo de administradores",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Não é possível remover a si mesmo desse grupo, pois você é um subadministrador",
+ "Not viable to remove user from the last group you are sub-admin of" : "Não é viável remover o usuário do último grupo do qual você é subadministrador",
+ "User does not exist" : "Usuário não existe",
+ "Group does not exist" : "Grupo não existe",
+ "User is not a sub-admin of this group" : "O usuário não é um subadministrador deste grupo",
+ "Email address not available" : "Endereço de e-mail não disponível",
+ "Sending email failed" : "Falha ao enviar e-mail",
+ "Email confirmation" : "Confirmação do endereço de e-mail",
+ "To enable the email address %s please click the button below." : "Para ativar o endereço de e-mail %s, por favor, clique no botão abaixo.",
+ "Confirm" : "Confirmar",
+ "Email was already removed from account and cannot be confirmed anymore." : "O e-mail já foi removido da conta e não pode mais ser confirmado.",
+ "Could not verify mail because the token is expired." : "Não foi possível verificar o e-mail porque o token expirou.",
+ "Could not verify mail because the token is invalid." : "Não foi possível verificar o e-mail porque o token é inválido.",
+ "An unexpected error occurred. Please contact your admin." : "Um erro inesperado ocorreu. Entre em contato com o seu administrador.",
+ "Email confirmation successful" : "E-mail confirmado com sucesso",
+ "Provisioning API" : "API de provisionamento",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Este aplicativo habilita um conjunto de APIs que sistemas externos podem usar para gerenciar contas, grupos e aplicativos.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Este aplicativo habilita um conjunto de APIs que sistemas externos podem usar para criar, editar, excluir e consultar atributos\n\t\tde conta, consultar, definir e remover grupos, definir cotas e consultar o armazenamento total usado no Nextcloud. As contas de administrador de grupo\n\t\ttambém podem consultar o Nextcloud e executar as mesmas funções de um administrador para os grupos que gerenciam. A API também permite\n\t\tque um administrador consulte os aplicativos ativos do Nextcloud, as informações do aplicativo e ative ou desative um aplicativo remotamente.\n\t\tDepois que o aplicativo é ativado, as solicitações HTTP podem ser usadas por meio de um cabeçalho Basic Auth para executar qualquer uma das funções\n\t\tlistadas acima. Mais informações estão disponíveis na documentação da API de Provisionamento, incluindo exemplos de solicitações\n\t\te respostas do servidor."
+},"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/ru.js b/apps/provisioning_api/l10n/ru.js
new file mode 100644
index 00000000000..1ba160a590b
--- /dev/null
+++ b/apps/provisioning_api/l10n/ru.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Для изменения этого параметра необходимо быть администратором или иметь соответствующие права.",
+ "Could not create non-existing user ID" : "Невозможно создать несуществующий идентификатор пользователя",
+ "User already exists" : "Пользователь уже существует",
+ "Group %1$s does not exist" : "Группа %1$s не существует",
+ "Insufficient privileges for group %1$s" : "Недостаточно прав для группы %1$s",
+ "No group specified (required for sub-admins)" : "Группа не указана (обязательно для субадминистраторов)",
+ "Sub-admin group does not exist" : "Группа субадминистратора не существует",
+ "Cannot create sub-admins for admin group" : "Нельзя назначить субадминистраторов для группы администраторов",
+ "No permissions to promote sub-admins" : "Недостаточно прав для назначения субадминистраторов",
+ "Invalid password value" : "Некорректное значение пароля",
+ "An email address is required, to send a password link to the user." : "Требуется адрес электронной почты для отправки ссылки на установку пароля пользователю.",
+ "Required email address was not provided" : "Не указан обязательный адрес электронной почты",
+ "User creation failed" : "Не удалось создать пользователя",
+ "Invalid quota value: %1$s" : "Недопустимое значение квоты: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Недопустимое значение квоты.%1$s превышает максимальное значение",
+ "Unlimited quota is forbidden on this instance" : "Безлимитная квота запрещена в этом инстансе",
+ "Setting the password is not supported by the users backend" : "Установка пароля не поддерживается используемой системой управления пользователями",
+ "Invalid language" : "Недопустимый язык",
+ "Invalid locale" : "Недопустимая локаль",
+ "Invalid first day of week" : "Недопустимый первый день недели",
+ "Cannot remove yourself from the admin group" : "Нельзя удалить себя из группы администраторов",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Нельзя удалить себя из этой группы, так как вы являетесь субадминистратором",
+ "Not viable to remove user from the last group you are sub-admin of" : "Нельзя удалить пользователя из последней группы, в которой вы являетесь субадминистратором",
+ "User does not exist" : "Пользователь не существует",
+ "Group does not exist" : "Группа не существует",
+ "User is not a sub-admin of this group" : "Пользователь не является субадминистратором этой группы",
+ "Email address not available" : "Адрес электронной почты недоступен",
+ "Sending email failed" : "Не удалось отправить письмо",
+ "Email confirmation" : "Подтверждение электронной почты",
+ "To enable the email address %s please click the button below." : "Чтобы включить адрес электронной почты %s, пожалуйста, нажмите на кнопку ниже.",
+ "Confirm" : "Подтвердить",
+ "Email was already removed from account and cannot be confirmed anymore." : "Электронная почта уже удалена из учетной записи и больше не может быть подтверждена.",
+ "Could not verify mail because the token is expired." : "Не удалось проверить почту, так как срок действия ключа подтверждения истек.",
+ "Could not verify mail because the token is invalid." : "Не удалось проверить почту, потому что ключ подтверждения недействителен.",
+ "An unexpected error occurred. Please contact your admin." : "Произошла неизвестная ошибка. Пожалуйста, свяжитесь с администратором.",
+ "Email confirmation successful" : "Электронная почта подтверждена",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Это приложение предоставляет набор API, которые внешние системы могут использовать для управления учётными записями, группами и приложениями.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Это приложение включает набор API, которые внешние системы могут использовать для создания, редактирования, удаления и запроса атрибутов учетной записи, запроса, установки и удаления групп, установки квоты и запроса общего хранилища, используемого в Nextcloud. Учетные записи администратора группы\nтакже могут запрашивать Nextcloud и выполнять те же функции, что и администратор для групп, которыми они управляют. API также позволяет\nадминистратору запрашивать активные приложения Nextcloud, информацию о приложении и включать или отключать приложение удаленно.\nПосле включения приложения HTTP-запросы можно использовать через заголовок Basic Auth для выполнения любой из функций,\nперечисленных выше. Дополнительная информация доступна в документации API Provisioning, включая примеры вызовов\nи ответы сервера."
+},
+"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/provisioning_api/l10n/ru.json b/apps/provisioning_api/l10n/ru.json
new file mode 100644
index 00000000000..35f64d94497
--- /dev/null
+++ b/apps/provisioning_api/l10n/ru.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Для изменения этого параметра необходимо быть администратором или иметь соответствующие права.",
+ "Could not create non-existing user ID" : "Невозможно создать несуществующий идентификатор пользователя",
+ "User already exists" : "Пользователь уже существует",
+ "Group %1$s does not exist" : "Группа %1$s не существует",
+ "Insufficient privileges for group %1$s" : "Недостаточно прав для группы %1$s",
+ "No group specified (required for sub-admins)" : "Группа не указана (обязательно для субадминистраторов)",
+ "Sub-admin group does not exist" : "Группа субадминистратора не существует",
+ "Cannot create sub-admins for admin group" : "Нельзя назначить субадминистраторов для группы администраторов",
+ "No permissions to promote sub-admins" : "Недостаточно прав для назначения субадминистраторов",
+ "Invalid password value" : "Некорректное значение пароля",
+ "An email address is required, to send a password link to the user." : "Требуется адрес электронной почты для отправки ссылки на установку пароля пользователю.",
+ "Required email address was not provided" : "Не указан обязательный адрес электронной почты",
+ "User creation failed" : "Не удалось создать пользователя",
+ "Invalid quota value: %1$s" : "Недопустимое значение квоты: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Недопустимое значение квоты.%1$s превышает максимальное значение",
+ "Unlimited quota is forbidden on this instance" : "Безлимитная квота запрещена в этом инстансе",
+ "Setting the password is not supported by the users backend" : "Установка пароля не поддерживается используемой системой управления пользователями",
+ "Invalid language" : "Недопустимый язык",
+ "Invalid locale" : "Недопустимая локаль",
+ "Invalid first day of week" : "Недопустимый первый день недели",
+ "Cannot remove yourself from the admin group" : "Нельзя удалить себя из группы администраторов",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Нельзя удалить себя из этой группы, так как вы являетесь субадминистратором",
+ "Not viable to remove user from the last group you are sub-admin of" : "Нельзя удалить пользователя из последней группы, в которой вы являетесь субадминистратором",
+ "User does not exist" : "Пользователь не существует",
+ "Group does not exist" : "Группа не существует",
+ "User is not a sub-admin of this group" : "Пользователь не является субадминистратором этой группы",
+ "Email address not available" : "Адрес электронной почты недоступен",
+ "Sending email failed" : "Не удалось отправить письмо",
+ "Email confirmation" : "Подтверждение электронной почты",
+ "To enable the email address %s please click the button below." : "Чтобы включить адрес электронной почты %s, пожалуйста, нажмите на кнопку ниже.",
+ "Confirm" : "Подтвердить",
+ "Email was already removed from account and cannot be confirmed anymore." : "Электронная почта уже удалена из учетной записи и больше не может быть подтверждена.",
+ "Could not verify mail because the token is expired." : "Не удалось проверить почту, так как срок действия ключа подтверждения истек.",
+ "Could not verify mail because the token is invalid." : "Не удалось проверить почту, потому что ключ подтверждения недействителен.",
+ "An unexpected error occurred. Please contact your admin." : "Произошла неизвестная ошибка. Пожалуйста, свяжитесь с администратором.",
+ "Email confirmation successful" : "Электронная почта подтверждена",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Это приложение предоставляет набор API, которые внешние системы могут использовать для управления учётными записями, группами и приложениями.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Это приложение включает набор API, которые внешние системы могут использовать для создания, редактирования, удаления и запроса атрибутов учетной записи, запроса, установки и удаления групп, установки квоты и запроса общего хранилища, используемого в Nextcloud. Учетные записи администратора группы\nтакже могут запрашивать Nextcloud и выполнять те же функции, что и администратор для групп, которыми они управляют. API также позволяет\nадминистратору запрашивать активные приложения Nextcloud, информацию о приложении и включать или отключать приложение удаленно.\nПосле включения приложения HTTP-запросы можно использовать через заголовок Basic Auth для выполнения любой из функций,\nперечисленных выше. Дополнительная информация доступна в документации API Provisioning, включая примеры вызовов\nи ответы сервера."
+},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/sk.js b/apps/provisioning_api/l10n/sk.js
new file mode 100644
index 00000000000..a6c5fda49cd
--- /dev/null
+++ b/apps/provisioning_api/l10n/sk.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Prihlásený používateľ musí byť správcom, alebo musí mať špeciálne právo na uprávu k tohoto nastavenia.",
+ "Could not create non-existing user ID" : "Nie je možné vytvoriť neexistujúce ID užívateľa",
+ "User already exists" : "Používateľ už existuje",
+ "Group %1$s does not exist" : "Skupina %1$s neexistuje",
+ "Insufficient privileges for group %1$s" : "Nedostatočné práva pre skupinu %1$s",
+ "No group specified (required for sub-admins)" : "Nebola zadaná žiadna skupina (potrebné pre sub-administrátorov)",
+ "Sub-admin group does not exist" : "Pod-administrátorská skupina neexistuje",
+ "Cannot create sub-admins for admin group" : "Nemôžem vytvoriť pod-administrátorskú skupinu pre administrátorskú skupinu",
+ "No permissions to promote sub-admins" : "Na povýšenie pod-administrátorov nie sú práva",
+ "Invalid password value" : "Neplatná hodnota hesla",
+ "An email address is required, to send a password link to the user." : "E-mail adresa je vyžadovaná pre poslanie odkazu uživateľovi pre reset hesla.",
+ "Required email address was not provided" : "Nebola zadaná požadovaná e-mailová adresa",
+ "Invalid quota value: %1$s" : "Neplatná hodnota kvóty: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Neplatná hodnota pre kvótu %1$s je väčšia ako maximálna kvóta",
+ "Unlimited quota is forbidden on this instance" : "Kvóta bez limitu nie je na tejto inštancii povolená",
+ "Setting the password is not supported by the users backend" : "Nastavenie hesla nie je pre podporované uživateľským backenom",
+ "Invalid language" : "Neplatný jazyk",
+ "Invalid locale" : "Neplatné miestne nastavenie",
+ "Invalid first day of week" : "Neplatný prvý deň týždňa",
+ "Cannot remove yourself from the admin group" : "Nemôžete odstrániť samého seba zo skupiny administrátorov",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Nemôžete odstrániť samého seba z tejto skupiny, pretože ste sub-administrátor",
+ "Not viable to remove user from the last group you are sub-admin of" : "Nie je možné odstrániť používateľa z poslednej skupiny, ktorej je pod-správcom",
+ "User does not exist" : "Užívateľ neexistuje",
+ "Group does not exist" : "Skupina neexistuje",
+ "User is not a sub-admin of this group" : "Užívateľ nie je sub-administrátor tejto skupiny",
+ "Email address not available" : "E-mailová adresa nie je dostupná",
+ "Sending email failed" : "Odosielanie e-mailu zlyhalo",
+ "Email confirmation" : "Overenie e-mailu",
+ "To enable the email address %s please click the button below." : "Pre povolenie e-mailovej adresy %s prosím kliknite na tlačítko nižšie.",
+ "Confirm" : "Potvrdiť",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mail bol odobraný z účtu a už nemôže byť overený.",
+ "Could not verify mail because the token is expired." : "Nepodarilo sa overiť e-mail, pretože platnosť tokenu uplynula.",
+ "Could not verify mail because the token is invalid." : "Nepodarilo sa overiť e-mail, pretože token je neplatný.",
+ "An unexpected error occurred. Please contact your admin." : "Vyskytla sa chyba. Prosím, kontaktujte svojho správcu.",
+ "Email confirmation successful" : "Overenie e-mailu bolo úspešné",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Táto aplikácia poskytuje sadu rozhraní API, ktoré môžu externé systémy používať na správu účtov, skupín a aplikácií.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Táto aplikácia poskytuje množinu rozhraní API, ktoré môžu externé systémy použiť pre vytváranie, úpravu, odstraňovanie a získavanie informácii o účte\natribúty, dotazovanie, nastavenie a odstránenie skupín, nastavenie kvóty a dotaz na celkové úložisko používané v Nextcloud. Skupinové správcovské účty\nmôžu tiež dopytovať Nextcloud a vykonávať rovnaké funkcie ako správca pre skupiny, ktoré spravujú. Rozhranie API tiež poskytuje\nsprávcu, ktorý bude vyhľadávať aktívne aplikácie Nextcloud, informácie o aplikácii a povolí alebo zakázuje aplikácie na diaľku.\nKeď je aplikácia povolená, požiadavky HTTP možno použiť prostredníctvom hlavičky Basic Auth na vykonanie ktorejkoľvek z funkcií\nuvedených vyššie. Viac informácií je k dispozícii v dokumentácii Provisioning API vrátane príkladov volaní\na odpovedí servera."
+},
+"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);");
diff --git a/apps/provisioning_api/l10n/sk.json b/apps/provisioning_api/l10n/sk.json
new file mode 100644
index 00000000000..81d6561a079
--- /dev/null
+++ b/apps/provisioning_api/l10n/sk.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Prihlásený používateľ musí byť správcom, alebo musí mať špeciálne právo na uprávu k tohoto nastavenia.",
+ "Could not create non-existing user ID" : "Nie je možné vytvoriť neexistujúce ID užívateľa",
+ "User already exists" : "Používateľ už existuje",
+ "Group %1$s does not exist" : "Skupina %1$s neexistuje",
+ "Insufficient privileges for group %1$s" : "Nedostatočné práva pre skupinu %1$s",
+ "No group specified (required for sub-admins)" : "Nebola zadaná žiadna skupina (potrebné pre sub-administrátorov)",
+ "Sub-admin group does not exist" : "Pod-administrátorská skupina neexistuje",
+ "Cannot create sub-admins for admin group" : "Nemôžem vytvoriť pod-administrátorskú skupinu pre administrátorskú skupinu",
+ "No permissions to promote sub-admins" : "Na povýšenie pod-administrátorov nie sú práva",
+ "Invalid password value" : "Neplatná hodnota hesla",
+ "An email address is required, to send a password link to the user." : "E-mail adresa je vyžadovaná pre poslanie odkazu uživateľovi pre reset hesla.",
+ "Required email address was not provided" : "Nebola zadaná požadovaná e-mailová adresa",
+ "Invalid quota value: %1$s" : "Neplatná hodnota kvóty: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Neplatná hodnota pre kvótu %1$s je väčšia ako maximálna kvóta",
+ "Unlimited quota is forbidden on this instance" : "Kvóta bez limitu nie je na tejto inštancii povolená",
+ "Setting the password is not supported by the users backend" : "Nastavenie hesla nie je pre podporované uživateľským backenom",
+ "Invalid language" : "Neplatný jazyk",
+ "Invalid locale" : "Neplatné miestne nastavenie",
+ "Invalid first day of week" : "Neplatný prvý deň týždňa",
+ "Cannot remove yourself from the admin group" : "Nemôžete odstrániť samého seba zo skupiny administrátorov",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Nemôžete odstrániť samého seba z tejto skupiny, pretože ste sub-administrátor",
+ "Not viable to remove user from the last group you are sub-admin of" : "Nie je možné odstrániť používateľa z poslednej skupiny, ktorej je pod-správcom",
+ "User does not exist" : "Užívateľ neexistuje",
+ "Group does not exist" : "Skupina neexistuje",
+ "User is not a sub-admin of this group" : "Užívateľ nie je sub-administrátor tejto skupiny",
+ "Email address not available" : "E-mailová adresa nie je dostupná",
+ "Sending email failed" : "Odosielanie e-mailu zlyhalo",
+ "Email confirmation" : "Overenie e-mailu",
+ "To enable the email address %s please click the button below." : "Pre povolenie e-mailovej adresy %s prosím kliknite na tlačítko nižšie.",
+ "Confirm" : "Potvrdiť",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-mail bol odobraný z účtu a už nemôže byť overený.",
+ "Could not verify mail because the token is expired." : "Nepodarilo sa overiť e-mail, pretože platnosť tokenu uplynula.",
+ "Could not verify mail because the token is invalid." : "Nepodarilo sa overiť e-mail, pretože token je neplatný.",
+ "An unexpected error occurred. Please contact your admin." : "Vyskytla sa chyba. Prosím, kontaktujte svojho správcu.",
+ "Email confirmation successful" : "Overenie e-mailu bolo úspešné",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Táto aplikácia poskytuje sadu rozhraní API, ktoré môžu externé systémy používať na správu účtov, skupín a aplikácií.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Táto aplikácia poskytuje množinu rozhraní API, ktoré môžu externé systémy použiť pre vytváranie, úpravu, odstraňovanie a získavanie informácii o účte\natribúty, dotazovanie, nastavenie a odstránenie skupín, nastavenie kvóty a dotaz na celkové úložisko používané v Nextcloud. Skupinové správcovské účty\nmôžu tiež dopytovať Nextcloud a vykonávať rovnaké funkcie ako správca pre skupiny, ktoré spravujú. Rozhranie API tiež poskytuje\nsprávcu, ktorý bude vyhľadávať aktívne aplikácie Nextcloud, informácie o aplikácii a povolí alebo zakázuje aplikácie na diaľku.\nKeď je aplikácia povolená, požiadavky HTTP možno použiť prostredníctvom hlavičky Basic Auth na vykonanie ktorejkoľvek z funkcií\nuvedených vyššie. Viac informácií je k dispozícii v dokumentácii Provisioning API vrátane príkladov volaní\na odpovedí servera."
+},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/sr.js b/apps/provisioning_api/l10n/sr.js
new file mode 100644
index 00000000000..18101d231d4
--- /dev/null
+++ b/apps/provisioning_api/l10n/sr.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Пријављени налог мора да буде администратор, или мора да поседује одобрење да уреди ово подешавање.",
+ "Could not create non-existing user ID" : "Не може да се креира ИД за корисника који не постоји",
+ "User already exists" : "Корисник већ постоји",
+ "Group %1$s does not exist" : "Група %1$s не постоји",
+ "Insufficient privileges for group %1$s" : "Нема довољно привилегија за групу %1$s",
+ "No group specified (required for sub-admins)" : "Није наведена ниједна група (потребно је за под-админе)",
+ "Sub-admin group does not exist" : "Не постоји група под-админа",
+ "Cannot create sub-admins for admin group" : "Не може да се креира група под-админа",
+ "No permissions to promote sub-admins" : "Нема дозвола да се унапреде под-админи",
+ "Invalid password value" : "Неисправна вредност лозинке",
+ "An email address is required, to send a password link to the user." : "За слање линка лозинке кориснику, неопходна је и-мејл адреса.",
+ "Required email address was not provided" : "Није наведена потребна и-мејл адреса",
+ "Invalid quota value: %1$s" : "Неисправна вредност квоте: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Неисправна вредност квоте. %1$s превазилази максималну квоту",
+ "Unlimited quota is forbidden on this instance" : "На овој инстанци је забрањена неограничена квота",
+ "Setting the password is not supported by the users backend" : "Позадински механизам за кориснике не подржава постављање лозинке",
+ "Invalid language" : "Неисправни језик",
+ "Invalid locale" : "Неисправни локалитет",
+ "Invalid first day of week" : "Неисправан први дан недеље",
+ "Cannot remove yourself from the admin group" : "Не можете да уклоните себе из админ групе",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Не можете да уклоните себе из ове групе јер сте под-админ",
+ "Not viable to remove user from the last group you are sub-admin of" : "Није одрживо да се уклони корисник иза последње групе којој сте под-админ",
+ "User does not exist" : "Корисник не постоји",
+ "Group does not exist" : "Група не постоји",
+ "User is not a sub-admin of this group" : "Корисник није под-админ ове групе",
+ "Email address not available" : "Није доступна и-мејл адреса",
+ "Sending email failed" : "Није успело слање и-мејла",
+ "Email confirmation" : "Потврда и-мејла",
+ "To enable the email address %s please click the button below." : "Ако желите да укључите и-мејл адресу %s молимо вас да кликнете на дугме испод.",
+ "Confirm" : "Потврди",
+ "Email was already removed from account and cannot be confirmed anymore." : "И-мејл је већ уклоњен из налога и више не може да се потврди.",
+ "Could not verify mail because the token is expired." : "Мејл не може да се потврди јер је истекла важност жетона.",
+ "Could not verify mail because the token is invalid." : "Мејл не може да се подрврди јер жетон не важи.",
+ "An unexpected error occurred. Please contact your admin." : "Дошло је до неочекиване грешке. Молимо вас да контактирате свог админа.",
+ "Email confirmation successful" : "Потврда и-мејла је успела",
+ "Provisioning API" : "API добављања ",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Ова апликација укључује скуп API-ја које спољни системи могу да користе за управљање налозима, групама и апликацијама.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Ова апликација укључује скуп API-апија које спољни ситеми могу да користе за креирање, уређивање, брисање корисника, постављају упите о\n\t\tатрибутима налога, креирају или уклањају групе, постављају упите о групама, постављају квоте и упите о укупном складишту које се користи у Nextcloud. Налози админ групе\n\t\tтакође могу да врше упит Nextcloud и обаве исте функције као админ за групе којима управљају. API такође омогућава\n\t\tадмину да врши упит о активним Nextcloud апликацијама, информацијама о апликацији и да даљински укључе или искључе апликацију.\n\t\tЈедном када се апликација укључи, било која функција наведена изнад може да се изврши прихватањем HTTP захтева кроз Basic Auth заглавље.\n\t\tВише информација се налази у докментацији за API добављања, као и примери позива\n\t\tи одговора сервера."
+},
+"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/provisioning_api/l10n/sr.json b/apps/provisioning_api/l10n/sr.json
new file mode 100644
index 00000000000..aa311566bfc
--- /dev/null
+++ b/apps/provisioning_api/l10n/sr.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Пријављени налог мора да буде администратор, или мора да поседује одобрење да уреди ово подешавање.",
+ "Could not create non-existing user ID" : "Не може да се креира ИД за корисника који не постоји",
+ "User already exists" : "Корисник већ постоји",
+ "Group %1$s does not exist" : "Група %1$s не постоји",
+ "Insufficient privileges for group %1$s" : "Нема довољно привилегија за групу %1$s",
+ "No group specified (required for sub-admins)" : "Није наведена ниједна група (потребно је за под-админе)",
+ "Sub-admin group does not exist" : "Не постоји група под-админа",
+ "Cannot create sub-admins for admin group" : "Не може да се креира група под-админа",
+ "No permissions to promote sub-admins" : "Нема дозвола да се унапреде под-админи",
+ "Invalid password value" : "Неисправна вредност лозинке",
+ "An email address is required, to send a password link to the user." : "За слање линка лозинке кориснику, неопходна је и-мејл адреса.",
+ "Required email address was not provided" : "Није наведена потребна и-мејл адреса",
+ "Invalid quota value: %1$s" : "Неисправна вредност квоте: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Неисправна вредност квоте. %1$s превазилази максималну квоту",
+ "Unlimited quota is forbidden on this instance" : "На овој инстанци је забрањена неограничена квота",
+ "Setting the password is not supported by the users backend" : "Позадински механизам за кориснике не подржава постављање лозинке",
+ "Invalid language" : "Неисправни језик",
+ "Invalid locale" : "Неисправни локалитет",
+ "Invalid first day of week" : "Неисправан први дан недеље",
+ "Cannot remove yourself from the admin group" : "Не можете да уклоните себе из админ групе",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Не можете да уклоните себе из ове групе јер сте под-админ",
+ "Not viable to remove user from the last group you are sub-admin of" : "Није одрживо да се уклони корисник иза последње групе којој сте под-админ",
+ "User does not exist" : "Корисник не постоји",
+ "Group does not exist" : "Група не постоји",
+ "User is not a sub-admin of this group" : "Корисник није под-админ ове групе",
+ "Email address not available" : "Није доступна и-мејл адреса",
+ "Sending email failed" : "Није успело слање и-мејла",
+ "Email confirmation" : "Потврда и-мејла",
+ "To enable the email address %s please click the button below." : "Ако желите да укључите и-мејл адресу %s молимо вас да кликнете на дугме испод.",
+ "Confirm" : "Потврди",
+ "Email was already removed from account and cannot be confirmed anymore." : "И-мејл је већ уклоњен из налога и више не може да се потврди.",
+ "Could not verify mail because the token is expired." : "Мејл не може да се потврди јер је истекла важност жетона.",
+ "Could not verify mail because the token is invalid." : "Мејл не може да се подрврди јер жетон не важи.",
+ "An unexpected error occurred. Please contact your admin." : "Дошло је до неочекиване грешке. Молимо вас да контактирате свог админа.",
+ "Email confirmation successful" : "Потврда и-мејла је успела",
+ "Provisioning API" : "API добављања ",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Ова апликација укључује скуп API-ја које спољни системи могу да користе за управљање налозима, групама и апликацијама.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Ова апликација укључује скуп API-апија које спољни ситеми могу да користе за креирање, уређивање, брисање корисника, постављају упите о\n\t\tатрибутима налога, креирају или уклањају групе, постављају упите о групама, постављају квоте и упите о укупном складишту које се користи у Nextcloud. Налози админ групе\n\t\tтакође могу да врше упит Nextcloud и обаве исте функције као админ за групе којима управљају. API такође омогућава\n\t\tадмину да врши упит о активним Nextcloud апликацијама, информацијама о апликацији и да даљински укључе или искључе апликацију.\n\t\tЈедном када се апликација укључи, било која функција наведена изнад може да се изврши прихватањем HTTP захтева кроз Basic Auth заглавље.\n\t\tВише информација се налази у докментацији за API добављања, као и примери позива\n\t\tи одговора сервера."
+},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/sv.js b/apps/provisioning_api/l10n/sv.js
new file mode 100644
index 00000000000..021f3bb02c0
--- /dev/null
+++ b/apps/provisioning_api/l10n/sv.js
@@ -0,0 +1,28 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Inloggat konto måste vara en administratör eller ha behörighet att ändra denna inställning.",
+ "Could not create non-existing user ID" : "Kunde inte skapa ej existerande användar-ID",
+ "User already exists" : "Användaren finns redan",
+ "Group %1$s does not exist" : "Grupp %1$s existerar inte",
+ "Insufficient privileges for group %1$s" : "Otillräckliga privilegier för grupp %1$s",
+ "No group specified (required for sub-admins)" : "Ingen grupp specificerad (krävs för underadministratörer)",
+ "Invalid password value" : "Ogiltigt lösenords-värde",
+ "Unlimited quota is forbidden on this instance" : "Obegränsad kvot är inte tillåtet på denna instans",
+ "Invalid language" : "Ogiltigt språk",
+ "Invalid locale" : "Ogiltigt språkområde",
+ "User does not exist" : "Användare existerar inte",
+ "Group does not exist" : "Grupp existerar inte",
+ "Email address not available" : "E-postadress är inte tillgänglig",
+ "Sending email failed" : "Utskick av e-postmeddelande misslyckades",
+ "Email confirmation" : "E-postverifikation",
+ "To enable the email address %s please click the button below." : "För att aktivera e-postadressen %s vänligen klicka på knappen nedanför.",
+ "Confirm" : "Bekräfta",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-postadress har redan tagits bort från konto och kan inte längre verifieras.",
+ "Could not verify mail because the token is expired." : "Kunde inte verifiera e-postadressen eftersom giltighetstiden för verifikationskoden har gått ut.",
+ "Could not verify mail because the token is invalid." : "Kunde inte verifiera e-postadressen eftersom verifikationskoden är inkorrekt.",
+ "An unexpected error occurred. Please contact your admin." : "Ett oväntat fel har uppkommit. Vänligen kontakta din administratör.",
+ "Email confirmation successful" : "E-postbekräftelsen lyckades",
+ "Provisioning API" : "Distribuerings API"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/sv.json b/apps/provisioning_api/l10n/sv.json
new file mode 100644
index 00000000000..2485c5d8966
--- /dev/null
+++ b/apps/provisioning_api/l10n/sv.json
@@ -0,0 +1,26 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Inloggat konto måste vara en administratör eller ha behörighet att ändra denna inställning.",
+ "Could not create non-existing user ID" : "Kunde inte skapa ej existerande användar-ID",
+ "User already exists" : "Användaren finns redan",
+ "Group %1$s does not exist" : "Grupp %1$s existerar inte",
+ "Insufficient privileges for group %1$s" : "Otillräckliga privilegier för grupp %1$s",
+ "No group specified (required for sub-admins)" : "Ingen grupp specificerad (krävs för underadministratörer)",
+ "Invalid password value" : "Ogiltigt lösenords-värde",
+ "Unlimited quota is forbidden on this instance" : "Obegränsad kvot är inte tillåtet på denna instans",
+ "Invalid language" : "Ogiltigt språk",
+ "Invalid locale" : "Ogiltigt språkområde",
+ "User does not exist" : "Användare existerar inte",
+ "Group does not exist" : "Grupp existerar inte",
+ "Email address not available" : "E-postadress är inte tillgänglig",
+ "Sending email failed" : "Utskick av e-postmeddelande misslyckades",
+ "Email confirmation" : "E-postverifikation",
+ "To enable the email address %s please click the button below." : "För att aktivera e-postadressen %s vänligen klicka på knappen nedanför.",
+ "Confirm" : "Bekräfta",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-postadress har redan tagits bort från konto och kan inte längre verifieras.",
+ "Could not verify mail because the token is expired." : "Kunde inte verifiera e-postadressen eftersom giltighetstiden för verifikationskoden har gått ut.",
+ "Could not verify mail because the token is invalid." : "Kunde inte verifiera e-postadressen eftersom verifikationskoden är inkorrekt.",
+ "An unexpected error occurred. Please contact your admin." : "Ett oväntat fel har uppkommit. Vänligen kontakta din administratör.",
+ "Email confirmation successful" : "E-postbekräftelsen lyckades",
+ "Provisioning API" : "Distribuerings API"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/sw.js b/apps/provisioning_api/l10n/sw.js
new file mode 100644
index 00000000000..5e6836a351c
--- /dev/null
+++ b/apps/provisioning_api/l10n/sw.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Akaunti iliyoingia lazima iwe msimamizi au iwe na idhini ya kuhariri mpangilio huu.",
+ "Could not create non-existing user ID" : "Haikuweza kuunda kitambulisho cha mtumiaji ambacho hakipo",
+ "User already exists" : "Mtumiaji tayari yupo",
+ "Group %1$s does not exist" : "Kikundi %1$s hakipo",
+ "Insufficient privileges for group %1$s" : "Mapendeleo yasiyotosha kwa kikundi %1$s",
+ "No group specified (required for sub-admins)" : "Hakuna kikundi kilichobainishwa (kinahitajika kwa wasimamizi wadogo)",
+ "Sub-admin group does not exist" : "Kikundi cha msimamizi mdogo hakipo",
+ "Cannot create sub-admins for admin group" : "Haiwezi kuunda wasimamizi wadogo wa kikundi cha wasimamizi",
+ "No permissions to promote sub-admins" : "Hakuna ruhusa za kukuza wasimamizi wadogo",
+ "Invalid password value" : "Thamani ya nenosiri si sahihi",
+ "An email address is required, to send a password link to the user." : "Barua pepe inahitajika, kutuma kiungo cha nenosiri kwa mtumiaji.",
+ "Required email address was not provided" : "Barua pepe inayohitajika haikutolewa",
+ "User creation failed" : "Imeshindwa kuunda mtumiaji",
+ "Invalid quota value: %1$s" : "Thamani ya mgao batili: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Thamani batili ya mgao. %1$s inazidi kiwango cha juu cha mgawo",
+ "Unlimited quota is forbidden on this instance" : "Kiasi kisicho na kikomo ni marufuku katika kesi hii",
+ "Setting the password is not supported by the users backend" : "Kuweka nenosiri hakuhimiliwi na mazingira ya nyuma ya watumiaji",
+ "Invalid language" : "Lugha batili",
+ "Invalid locale" : "Lugha isiyo sahihi",
+ "Invalid first day of week" : "Siku ya kwanza ya wiki si sahihi",
+ "Cannot remove yourself from the admin group" : "Huwezi kujiondoa kutoka kwa kikundi cha wasimamizi",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Huwezi kujiondoa kwenye kikundi hiki kwa kuwa wewe ni msimamizi mdogo",
+ "Not viable to remove user from the last group you are sub-admin of" : "Haiwezekani kuondoa mtumiaji kutoka kwa kikundi cha mwisho ambacho wewe ni msimamizi mdogo",
+ "User does not exist" : "Mtumiaji hayupo",
+ "Group does not exist" : "Kikundi hakipo",
+ "User is not a sub-admin of this group" : "Mtumiaji si msimamizi mdogo wa kikundi hiki",
+ "Email address not available" : "Anwani ya barua pepe haipatikani",
+ "Sending email failed" : "Imeshindwa kutuma barua pepe",
+ "Email confirmation" : "Uthibitishaji wa barua pepe",
+ "To enable the email address %s please click the button below." : "Ili kuwezesha anwani ya barua pepe %s tafadhali bofya kitufe kilicho hapa chini.",
+ "Confirm" : "Thibitisha",
+ "Email was already removed from account and cannot be confirmed anymore." : "Barua pepe ilikuwa tayari imeondolewa kwenye akaunti na haiwezi kuthibitishwa tena.",
+ "Could not verify mail because the token is expired." : "Haikuweza kuthibitisha barua kwa sababu tokeni imeisha muda wake.",
+ "Could not verify mail because the token is invalid." : "Haikuweza kuthibitisha barua kwa sababu tokeni si sahihi.",
+ "An unexpected error occurred. Please contact your admin." : "Hitilafu isiyotarajiwa imetokea. Tafadhali wasiliana na msimamizi wako.",
+ "Email confirmation successful" : "Uthibitisho wa barua pepe umefanikiwa",
+ "Provisioning API" : "API ya utoaji",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Programu hii huwezesha seti ya API ambazo mifumo ya nje inaweza kutumia kudhibiti akaunti, vikundi na programu.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Programu hii huwezesha seti ya API ambazo mifumo ya nje inaweza kutumia kuunda, kuhariri, kufuta na kuuliza akaunti\n\t\tsifa, uliza, weka na uondoe vikundi, weka kiasi na uulize jumla ya hifadhi inayotumika kwenye Nextcloud. Akaunti za msimamizi wa kikundi\n\t\tanaweza pia kuuliza Nextcloud na kutekeleza utendakazi sawa na msimamizi wa vikundi anavyosimamia. API pia inawezesha\n\t\tmsimamizi ili kuuliza maswali kuhusu programu zinazotumika za Nextcloud, maelezo ya programu, na kuwasha au kuzima programu kwa mbali.\n\t\tBaada ya programu kuwashwa, maombi ya HTTP yanaweza kutumika kupitia kichwa cha Uandishi wa Msingi kutekeleza utendakazi wowote.\n\t\tiliyoorodheshwa hapo juu. Maelezo zaidi yanapatikana katika hati za API ya Utoaji, ikijumuisha simu za mfano\n\t\tna majibu ya seva."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/sw.json b/apps/provisioning_api/l10n/sw.json
new file mode 100644
index 00000000000..0b1c4555d81
--- /dev/null
+++ b/apps/provisioning_api/l10n/sw.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Akaunti iliyoingia lazima iwe msimamizi au iwe na idhini ya kuhariri mpangilio huu.",
+ "Could not create non-existing user ID" : "Haikuweza kuunda kitambulisho cha mtumiaji ambacho hakipo",
+ "User already exists" : "Mtumiaji tayari yupo",
+ "Group %1$s does not exist" : "Kikundi %1$s hakipo",
+ "Insufficient privileges for group %1$s" : "Mapendeleo yasiyotosha kwa kikundi %1$s",
+ "No group specified (required for sub-admins)" : "Hakuna kikundi kilichobainishwa (kinahitajika kwa wasimamizi wadogo)",
+ "Sub-admin group does not exist" : "Kikundi cha msimamizi mdogo hakipo",
+ "Cannot create sub-admins for admin group" : "Haiwezi kuunda wasimamizi wadogo wa kikundi cha wasimamizi",
+ "No permissions to promote sub-admins" : "Hakuna ruhusa za kukuza wasimamizi wadogo",
+ "Invalid password value" : "Thamani ya nenosiri si sahihi",
+ "An email address is required, to send a password link to the user." : "Barua pepe inahitajika, kutuma kiungo cha nenosiri kwa mtumiaji.",
+ "Required email address was not provided" : "Barua pepe inayohitajika haikutolewa",
+ "User creation failed" : "Imeshindwa kuunda mtumiaji",
+ "Invalid quota value: %1$s" : "Thamani ya mgao batili: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Thamani batili ya mgao. %1$s inazidi kiwango cha juu cha mgawo",
+ "Unlimited quota is forbidden on this instance" : "Kiasi kisicho na kikomo ni marufuku katika kesi hii",
+ "Setting the password is not supported by the users backend" : "Kuweka nenosiri hakuhimiliwi na mazingira ya nyuma ya watumiaji",
+ "Invalid language" : "Lugha batili",
+ "Invalid locale" : "Lugha isiyo sahihi",
+ "Invalid first day of week" : "Siku ya kwanza ya wiki si sahihi",
+ "Cannot remove yourself from the admin group" : "Huwezi kujiondoa kutoka kwa kikundi cha wasimamizi",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Huwezi kujiondoa kwenye kikundi hiki kwa kuwa wewe ni msimamizi mdogo",
+ "Not viable to remove user from the last group you are sub-admin of" : "Haiwezekani kuondoa mtumiaji kutoka kwa kikundi cha mwisho ambacho wewe ni msimamizi mdogo",
+ "User does not exist" : "Mtumiaji hayupo",
+ "Group does not exist" : "Kikundi hakipo",
+ "User is not a sub-admin of this group" : "Mtumiaji si msimamizi mdogo wa kikundi hiki",
+ "Email address not available" : "Anwani ya barua pepe haipatikani",
+ "Sending email failed" : "Imeshindwa kutuma barua pepe",
+ "Email confirmation" : "Uthibitishaji wa barua pepe",
+ "To enable the email address %s please click the button below." : "Ili kuwezesha anwani ya barua pepe %s tafadhali bofya kitufe kilicho hapa chini.",
+ "Confirm" : "Thibitisha",
+ "Email was already removed from account and cannot be confirmed anymore." : "Barua pepe ilikuwa tayari imeondolewa kwenye akaunti na haiwezi kuthibitishwa tena.",
+ "Could not verify mail because the token is expired." : "Haikuweza kuthibitisha barua kwa sababu tokeni imeisha muda wake.",
+ "Could not verify mail because the token is invalid." : "Haikuweza kuthibitisha barua kwa sababu tokeni si sahihi.",
+ "An unexpected error occurred. Please contact your admin." : "Hitilafu isiyotarajiwa imetokea. Tafadhali wasiliana na msimamizi wako.",
+ "Email confirmation successful" : "Uthibitisho wa barua pepe umefanikiwa",
+ "Provisioning API" : "API ya utoaji",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Programu hii huwezesha seti ya API ambazo mifumo ya nje inaweza kutumia kudhibiti akaunti, vikundi na programu.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Programu hii huwezesha seti ya API ambazo mifumo ya nje inaweza kutumia kuunda, kuhariri, kufuta na kuuliza akaunti\n\t\tsifa, uliza, weka na uondoe vikundi, weka kiasi na uulize jumla ya hifadhi inayotumika kwenye Nextcloud. Akaunti za msimamizi wa kikundi\n\t\tanaweza pia kuuliza Nextcloud na kutekeleza utendakazi sawa na msimamizi wa vikundi anavyosimamia. API pia inawezesha\n\t\tmsimamizi ili kuuliza maswali kuhusu programu zinazotumika za Nextcloud, maelezo ya programu, na kuwasha au kuzima programu kwa mbali.\n\t\tBaada ya programu kuwashwa, maombi ya HTTP yanaweza kutumika kupitia kichwa cha Uandishi wa Msingi kutekeleza utendakazi wowote.\n\t\tiliyoorodheshwa hapo juu. Maelezo zaidi yanapatikana katika hati za API ya Utoaji, ikijumuisha simu za mfano\n\t\tna majibu ya seva."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/tr.js b/apps/provisioning_api/l10n/tr.js
new file mode 100644
index 00000000000..db6d11429bb
--- /dev/null
+++ b/apps/provisioning_api/l10n/tr.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Oturum açmış hesap bir yönetici olmalı ya da bu ayarı düzenleme izni olmalıdır.",
+ "Could not create non-existing user ID" : "Var olmayan kullanıcı kimliği oluşturulamadı",
+ "User already exists" : "Kullanıcı zaten var",
+ "Group %1$s does not exist" : "%1$s grubu bulunamadı",
+ "Insufficient privileges for group %1$s" : "%1$s grubu için izinler yetersiz",
+ "No group specified (required for sub-admins)" : "Herhangi bir grup belirtilmemiş (alt yöneticiler için gereklidir)",
+ "Sub-admin group does not exist" : "Alt yönetici grubu bulunamadı",
+ "Cannot create sub-admins for admin group" : "Yönetici grubu için alt yöneticiler oluşturulamadı",
+ "No permissions to promote sub-admins" : "Alt yöneticileri yükseltme izni yok",
+ "Invalid password value" : "Parola değeri geçersiz",
+ "An email address is required, to send a password link to the user." : "Kullanıcıya bir parola bağlantısı gönderebilmek için bir e-posta adresi gereklidir.",
+ "Required email address was not provided" : "Gerekli e-posta adresi belirtilmemiş",
+ "Invalid quota value: %1$s" : "Kota değeri geçersiz: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Kota değeri geçersiz. %1$s en fazla kota değerini aşıyor",
+ "Unlimited quota is forbidden on this instance" : "Bu kopyada sınırsız kota kullanılamaz",
+ "Setting the password is not supported by the users backend" : "Kullanıcı arka yüzünden parola ayarlanamaz",
+ "Invalid language" : "Dil geçersiz",
+ "Invalid locale" : "Yerel ayar geçersiz",
+ "Invalid first day of week" : "Haftanın ilk günü geçersiz",
+ "Cannot remove yourself from the admin group" : "Kendinizi yönetici grubundan çıkaramazsınız",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Bir alt yönetici olduğunuzdan kendinizi bu gruptan çıkaramazsınız",
+ "Not viable to remove user from the last group you are sub-admin of" : "Alt yöneticisi olduğunuz son gruptan kullanıcıyı kaldıramazsınız",
+ "User does not exist" : "Kullanıcı bulunamadı",
+ "Group does not exist" : "Grup bulunamadı",
+ "User is not a sub-admin of this group" : "Kullanıcı bu grubun bir alt yöneticisi değil",
+ "Email address not available" : "E-posta adresi kullanılamaz",
+ "Sending email failed" : "E-posta gönderilemedi",
+ "Email confirmation" : "E-posta doğrulaması",
+ "To enable the email address %s please click the button below." : "%s e-posta adresini doğrulamak için aşağıdaki düğmeye tıklayın.",
+ "Confirm" : "Onayla",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-posta hesaptan kaldırılmış olduğundan artık onaylanamaz.",
+ "Could not verify mail because the token is expired." : "Kodun geçerlilik süresi dolmuş olduğundan e-posta doğrulanamadı.",
+ "Could not verify mail because the token is invalid." : "Kod geçersiz olduğundan e-posta doğrulanamadı.",
+ "An unexpected error occurred. Please contact your admin." : "Beklenmeyen bir sorun çıktı. Lütfen BT yöneticiniz ile görüşün.",
+ "Email confirmation successful" : "E-posta onaylandı",
+ "Provisioning API" : "Karşılama API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Bu uygulama, dış sistemlerin hesapları, grupları ve uygulamaları yönetmek için kullanabileceği bir dizi API uygulaması sağlar.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Bu uygulama, dış sistemlerin hesap özelliklerini eklemesi, düzenlemesi ve sorgulaması, grupları ayarlaması\n\t\tve silmesi ile Nextcloud tarafından kullanılan toplam depolama alanını sorgulaması için kullanabileceği\n\t\t bir dizi API uygulaması sağlar. Grup yöneticisi olan hesaplar da Nextcloud sorguları yürüterek yönettikleri\n\t\tgruplar üzerinde aynı işlemleri yöneticiler gibi yapabilirler. API uygulaması ayrıca kullanıma alınmış Nextcloud uygulamalarını\n\t\t ve uygulama bilgilerini sorgulayabilir ve uygulamaları uzaktan kullanıma alıp, kullanımdan kaldırabilir. Uygulama\n\t\tkullanıma alındıktan sonra yukarıdaki işlemleri yapmak için Temel kimlik doğrulaması üst bilgisi ile HTTP istekleri\n\t\tyapılabilir. Ayrıntılı bilgi almak ve örnek çağrılar ile sunucu yanıtlarını görmek için API hazırlama belgesine bakabilirsiniz."
+},
+"nplurals=2; plural=(n > 1);");
diff --git a/apps/provisioning_api/l10n/tr.json b/apps/provisioning_api/l10n/tr.json
new file mode 100644
index 00000000000..3e4a591bb5f
--- /dev/null
+++ b/apps/provisioning_api/l10n/tr.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Oturum açmış hesap bir yönetici olmalı ya da bu ayarı düzenleme izni olmalıdır.",
+ "Could not create non-existing user ID" : "Var olmayan kullanıcı kimliği oluşturulamadı",
+ "User already exists" : "Kullanıcı zaten var",
+ "Group %1$s does not exist" : "%1$s grubu bulunamadı",
+ "Insufficient privileges for group %1$s" : "%1$s grubu için izinler yetersiz",
+ "No group specified (required for sub-admins)" : "Herhangi bir grup belirtilmemiş (alt yöneticiler için gereklidir)",
+ "Sub-admin group does not exist" : "Alt yönetici grubu bulunamadı",
+ "Cannot create sub-admins for admin group" : "Yönetici grubu için alt yöneticiler oluşturulamadı",
+ "No permissions to promote sub-admins" : "Alt yöneticileri yükseltme izni yok",
+ "Invalid password value" : "Parola değeri geçersiz",
+ "An email address is required, to send a password link to the user." : "Kullanıcıya bir parola bağlantısı gönderebilmek için bir e-posta adresi gereklidir.",
+ "Required email address was not provided" : "Gerekli e-posta adresi belirtilmemiş",
+ "Invalid quota value: %1$s" : "Kota değeri geçersiz: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Kota değeri geçersiz. %1$s en fazla kota değerini aşıyor",
+ "Unlimited quota is forbidden on this instance" : "Bu kopyada sınırsız kota kullanılamaz",
+ "Setting the password is not supported by the users backend" : "Kullanıcı arka yüzünden parola ayarlanamaz",
+ "Invalid language" : "Dil geçersiz",
+ "Invalid locale" : "Yerel ayar geçersiz",
+ "Invalid first day of week" : "Haftanın ilk günü geçersiz",
+ "Cannot remove yourself from the admin group" : "Kendinizi yönetici grubundan çıkaramazsınız",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Bir alt yönetici olduğunuzdan kendinizi bu gruptan çıkaramazsınız",
+ "Not viable to remove user from the last group you are sub-admin of" : "Alt yöneticisi olduğunuz son gruptan kullanıcıyı kaldıramazsınız",
+ "User does not exist" : "Kullanıcı bulunamadı",
+ "Group does not exist" : "Grup bulunamadı",
+ "User is not a sub-admin of this group" : "Kullanıcı bu grubun bir alt yöneticisi değil",
+ "Email address not available" : "E-posta adresi kullanılamaz",
+ "Sending email failed" : "E-posta gönderilemedi",
+ "Email confirmation" : "E-posta doğrulaması",
+ "To enable the email address %s please click the button below." : "%s e-posta adresini doğrulamak için aşağıdaki düğmeye tıklayın.",
+ "Confirm" : "Onayla",
+ "Email was already removed from account and cannot be confirmed anymore." : "E-posta hesaptan kaldırılmış olduğundan artık onaylanamaz.",
+ "Could not verify mail because the token is expired." : "Kodun geçerlilik süresi dolmuş olduğundan e-posta doğrulanamadı.",
+ "Could not verify mail because the token is invalid." : "Kod geçersiz olduğundan e-posta doğrulanamadı.",
+ "An unexpected error occurred. Please contact your admin." : "Beklenmeyen bir sorun çıktı. Lütfen BT yöneticiniz ile görüşün.",
+ "Email confirmation successful" : "E-posta onaylandı",
+ "Provisioning API" : "Karşılama API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Bu uygulama, dış sistemlerin hesapları, grupları ve uygulamaları yönetmek için kullanabileceği bir dizi API uygulaması sağlar.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Bu uygulama, dış sistemlerin hesap özelliklerini eklemesi, düzenlemesi ve sorgulaması, grupları ayarlaması\n\t\tve silmesi ile Nextcloud tarafından kullanılan toplam depolama alanını sorgulaması için kullanabileceği\n\t\t bir dizi API uygulaması sağlar. Grup yöneticisi olan hesaplar da Nextcloud sorguları yürüterek yönettikleri\n\t\tgruplar üzerinde aynı işlemleri yöneticiler gibi yapabilirler. API uygulaması ayrıca kullanıma alınmış Nextcloud uygulamalarını\n\t\t ve uygulama bilgilerini sorgulayabilir ve uygulamaları uzaktan kullanıma alıp, kullanımdan kaldırabilir. Uygulama\n\t\tkullanıma alındıktan sonra yukarıdaki işlemleri yapmak için Temel kimlik doğrulaması üst bilgisi ile HTTP istekleri\n\t\tyapılabilir. Ayrıntılı bilgi almak ve örnek çağrılar ile sunucu yanıtlarını görmek için API hazırlama belgesine bakabilirsiniz."
+},"pluralForm" :"nplurals=2; plural=(n > 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/ug.js b/apps/provisioning_api/l10n/ug.js
new file mode 100644
index 00000000000..d6481eda90c
--- /dev/null
+++ b/apps/provisioning_api/l10n/ug.js
@@ -0,0 +1,43 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "ھېساباتقا كىرگەن چوقۇم باشقۇرغۇچى بولۇشى ياكى بۇ تەڭشەكنى تەھرىرلەش ھوقۇقى بولۇشى كېرەك.",
+ "Could not create non-existing user ID" : "مەۋجۇت ئىشلەتكۈچى كىملىكىنى قۇرالمىدى",
+ "User already exists" : "ئىشلەتكۈچى ئاللىبۇرۇن مەۋجۇت",
+ "Group %1$s does not exist" : "گۇرۇپپا%1 $ s مەۋجۇت ئەمەس",
+ "Insufficient privileges for group %1$s" : "گۇرۇپپا%1 $ s ئۈچۈن ئىمتىياز يېتەرلىك ئەمەس",
+ "No group specified (required for sub-admins)" : "ھېچقانداق گۇرۇپپا بەلگىلەنمىگەن (تارماق باشقۇرغۇچىلار ئۈچۈن تەلەپ قىلىنىدۇ)",
+ "Sub-admin group does not exist" : "تارماق باشقۇرغۇچى گۇرۇپپىسى مەۋجۇت ئەمەس",
+ "Cannot create sub-admins for admin group" : "باشقۇرۇش گۇرۇپپىسى ئۈچۈن تارماق باشقۇرغۇچى قۇرالمايدۇ",
+ "No permissions to promote sub-admins" : "تارماق باشقۇرغۇچىلارنى تەشۋىق قىلىشقا ئىجازەت يوق",
+ "Invalid password value" : "پارول قىممىتى ئىناۋەتسىز",
+ "An email address is required, to send a password link to the user." : "ئىشلەتكۈچىگە پارول ئۇلىنىشى ئۈچۈن ئېلېكترونلۇق خەت ئادرېسى تەلەپ قىلىنىدۇ.",
+ "Required email address was not provided" : "تەلەپ قىلىنغان ئېلېكترونلۇق خەت ئادرېسى تەمىنلەنمىگەن",
+ "Invalid quota value: %1$s" : "ئىناۋەتلىك نورما قىممىتى:%1 $ s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "نورما قىممىتى ئىناۋەتسىز. %1 $ s ئەڭ يۇقىرى نورمىدىن ئېشىپ كەتتى",
+ "Unlimited quota is forbidden on this instance" : "بۇ ئەھۋالدا چەكلىمىسىز نورما چەكلەنگەن",
+ "Setting the password is not supported by the users backend" : "پارول بەلگىلەشنى ئىشلەتكۈچى ئارقا سۇپىسى قوللىمايدۇ",
+ "Invalid language" : "ئىناۋەتسىز تىل",
+ "Invalid locale" : "ئىناۋەتسىز",
+ "Invalid first day of week" : "ھەپتىنىڭ بىرىنچى كۈنى ئىناۋەتسىز",
+ "Cannot remove yourself from the admin group" : "ئۆزىڭىزنى باشقۇرۇش گۇرۇپپىسىدىن ئۆچۈرەلمەيسىز",
+ "Cannot remove yourself from this group as you are a sub-admin" : "تارماق باشقۇرغۇچى بولغانلىقىڭىز ئۈچۈن ئۆزىڭىزنى بۇ گۇرۇپپىدىن ئۆچۈرەلمەيسىز",
+ "Not viable to remove user from the last group you are sub-admin of" : "سىز ئاخىرقى باشقۇرغۇچى بولغان ئاخىرقى گۇرۇپپىدىن ئىشلەتكۈچىنى چىقىرىۋېتىش مۇمكىن ئەمەس",
+ "User does not exist" : "ئىشلەتكۈچى مەۋجۇت ئەمەس",
+ "Group does not exist" : "گۇرۇپپا مەۋجۇت ئەمەس",
+ "User is not a sub-admin of this group" : "ئىشلەتكۈچى بۇ گۇرۇپپىنىڭ تارماق باشقۇرغۇچىسى ئەمەس",
+ "Email address not available" : "ئېلېكترونلۇق خەت ئادرېسى يوق",
+ "Sending email failed" : "ئېلېكترونلۇق خەت ئەۋەتىش مەغلۇپ بولدى",
+ "Email confirmation" : "ئېلېكترونلۇق خەت جەزملەشتۈرۈش",
+ "To enable the email address %s please click the button below." : "ئېلېكترونلۇق خەت ئادرېسىنى% s قوزغىتىش ئۈچۈن تۆۋەندىكى كۇنۇپكىنى بېسىڭ.",
+ "Confirm" : "جەزملەشتۈرۈڭ",
+ "Email was already removed from account and cannot be confirmed anymore." : "ئېلېكترونلۇق خەت ئاللىبۇرۇن ھېساباتتىن ئۆچۈرۈۋېتىلدى ، ئەمدى جەزملەشتۈرگىلى بولمايدۇ.",
+ "Could not verify mail because the token is expired." : "خەتنىڭ ۋاقتى توشقانلىقتىن خەتنى دەلىللىيەلمىدى.",
+ "Could not verify mail because the token is invalid." : "خەتكۈچ ئىناۋەتسىز بولغاچقا خەتنى دەلىللىيەلمىدى.",
+ "An unexpected error occurred. Please contact your admin." : "ئويلىمىغان خاتالىق يۈز بەردى. باشقۇرغۇچىڭىز بىلەن ئالاقىلىشىڭ.",
+ "Email confirmation successful" : "ئېلېكترونلۇق خەت جەزملەشتۈرۈلدى",
+ "Provisioning API" : "API بىلەن تەمىنلەش",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "بۇ پروگرامما سىرتقى سىستېمىلار ھېسابات ، گۇرۇپپا ۋە ئەپلەرنى باشقۇرۇشتا ئىشلىتىدىغان بىر يۈرۈش API لارنى قوزغىتىدۇ.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "بۇ پروگرامما سىرتقى سىستېمىلار ھېسابات قۇرۇش ، تەھرىرلەش ، ئۆچۈرۈش ۋە سۈرۈشتۈرۈش ئۈچۈن ئىشلىتىدىغان بىر يۈرۈش API لارنى قوزغىتىدۇ\n\t\tخاسلىق ، سۈرۈشتۈرۈش ، گۇرۇپپىلارنى تەڭشەش ۋە ئۆچۈرۈش ، Nextcloud دا ئىشلىتىلىدىغان نورما ۋە سوئال ئومۇمىي ساقلاش. گۇرۇپپا باشقۇرۇش ھېساباتى\n\t\tNextcloud دىن سوئال سوراپ ، ئۇلار باشقۇرىدىغان گۇرۇپپىلارنىڭ باشقۇرغۇچىسى بىلەن ئوخشاش ئىقتىدارلارنى ئىشلىتەلەيدۇ. API يەنە قوزغىتىدۇ\n\t\tئاكتىپ Nextcloud قوللىنىشچان پروگراممىلىرى ، قوللىنىشچان ئۇچۇرلار ۋە ئەپنى يىراقتىن قوزغىتىش ياكى چەكلەش ئۈچۈن باشقۇرغۇچى.\n\t\tبۇ دېتال قوزغىتىلغاندىن كېيىن ، HTTP تەلەپلىرىنى Basic Auth ماۋزۇسى ئارقىلىق ھەر قانداق ئىقتىدارنى ئورۇندىغىلى بولىدۇ\n\t\tيۇقىرىدا كۆرسىتىلگەن. تەمىنلىگۈچى API ھۆججىتىدە تېخىمۇ كۆپ ئۇچۇرلار بار ، مەسىلەن تېلېفون چاقىرىش\n\t\tۋە مۇلازىمېتىرنىڭ ئىنكاسى."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/provisioning_api/l10n/ug.json b/apps/provisioning_api/l10n/ug.json
new file mode 100644
index 00000000000..7ce959ce9c9
--- /dev/null
+++ b/apps/provisioning_api/l10n/ug.json
@@ -0,0 +1,41 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "ھېساباتقا كىرگەن چوقۇم باشقۇرغۇچى بولۇشى ياكى بۇ تەڭشەكنى تەھرىرلەش ھوقۇقى بولۇشى كېرەك.",
+ "Could not create non-existing user ID" : "مەۋجۇت ئىشلەتكۈچى كىملىكىنى قۇرالمىدى",
+ "User already exists" : "ئىشلەتكۈچى ئاللىبۇرۇن مەۋجۇت",
+ "Group %1$s does not exist" : "گۇرۇپپا%1 $ s مەۋجۇت ئەمەس",
+ "Insufficient privileges for group %1$s" : "گۇرۇپپا%1 $ s ئۈچۈن ئىمتىياز يېتەرلىك ئەمەس",
+ "No group specified (required for sub-admins)" : "ھېچقانداق گۇرۇپپا بەلگىلەنمىگەن (تارماق باشقۇرغۇچىلار ئۈچۈن تەلەپ قىلىنىدۇ)",
+ "Sub-admin group does not exist" : "تارماق باشقۇرغۇچى گۇرۇپپىسى مەۋجۇت ئەمەس",
+ "Cannot create sub-admins for admin group" : "باشقۇرۇش گۇرۇپپىسى ئۈچۈن تارماق باشقۇرغۇچى قۇرالمايدۇ",
+ "No permissions to promote sub-admins" : "تارماق باشقۇرغۇچىلارنى تەشۋىق قىلىشقا ئىجازەت يوق",
+ "Invalid password value" : "پارول قىممىتى ئىناۋەتسىز",
+ "An email address is required, to send a password link to the user." : "ئىشلەتكۈچىگە پارول ئۇلىنىشى ئۈچۈن ئېلېكترونلۇق خەت ئادرېسى تەلەپ قىلىنىدۇ.",
+ "Required email address was not provided" : "تەلەپ قىلىنغان ئېلېكترونلۇق خەت ئادرېسى تەمىنلەنمىگەن",
+ "Invalid quota value: %1$s" : "ئىناۋەتلىك نورما قىممىتى:%1 $ s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "نورما قىممىتى ئىناۋەتسىز. %1 $ s ئەڭ يۇقىرى نورمىدىن ئېشىپ كەتتى",
+ "Unlimited quota is forbidden on this instance" : "بۇ ئەھۋالدا چەكلىمىسىز نورما چەكلەنگەن",
+ "Setting the password is not supported by the users backend" : "پارول بەلگىلەشنى ئىشلەتكۈچى ئارقا سۇپىسى قوللىمايدۇ",
+ "Invalid language" : "ئىناۋەتسىز تىل",
+ "Invalid locale" : "ئىناۋەتسىز",
+ "Invalid first day of week" : "ھەپتىنىڭ بىرىنچى كۈنى ئىناۋەتسىز",
+ "Cannot remove yourself from the admin group" : "ئۆزىڭىزنى باشقۇرۇش گۇرۇپپىسىدىن ئۆچۈرەلمەيسىز",
+ "Cannot remove yourself from this group as you are a sub-admin" : "تارماق باشقۇرغۇچى بولغانلىقىڭىز ئۈچۈن ئۆزىڭىزنى بۇ گۇرۇپپىدىن ئۆچۈرەلمەيسىز",
+ "Not viable to remove user from the last group you are sub-admin of" : "سىز ئاخىرقى باشقۇرغۇچى بولغان ئاخىرقى گۇرۇپپىدىن ئىشلەتكۈچىنى چىقىرىۋېتىش مۇمكىن ئەمەس",
+ "User does not exist" : "ئىشلەتكۈچى مەۋجۇت ئەمەس",
+ "Group does not exist" : "گۇرۇپپا مەۋجۇت ئەمەس",
+ "User is not a sub-admin of this group" : "ئىشلەتكۈچى بۇ گۇرۇپپىنىڭ تارماق باشقۇرغۇچىسى ئەمەس",
+ "Email address not available" : "ئېلېكترونلۇق خەت ئادرېسى يوق",
+ "Sending email failed" : "ئېلېكترونلۇق خەت ئەۋەتىش مەغلۇپ بولدى",
+ "Email confirmation" : "ئېلېكترونلۇق خەت جەزملەشتۈرۈش",
+ "To enable the email address %s please click the button below." : "ئېلېكترونلۇق خەت ئادرېسىنى% s قوزغىتىش ئۈچۈن تۆۋەندىكى كۇنۇپكىنى بېسىڭ.",
+ "Confirm" : "جەزملەشتۈرۈڭ",
+ "Email was already removed from account and cannot be confirmed anymore." : "ئېلېكترونلۇق خەت ئاللىبۇرۇن ھېساباتتىن ئۆچۈرۈۋېتىلدى ، ئەمدى جەزملەشتۈرگىلى بولمايدۇ.",
+ "Could not verify mail because the token is expired." : "خەتنىڭ ۋاقتى توشقانلىقتىن خەتنى دەلىللىيەلمىدى.",
+ "Could not verify mail because the token is invalid." : "خەتكۈچ ئىناۋەتسىز بولغاچقا خەتنى دەلىللىيەلمىدى.",
+ "An unexpected error occurred. Please contact your admin." : "ئويلىمىغان خاتالىق يۈز بەردى. باشقۇرغۇچىڭىز بىلەن ئالاقىلىشىڭ.",
+ "Email confirmation successful" : "ئېلېكترونلۇق خەت جەزملەشتۈرۈلدى",
+ "Provisioning API" : "API بىلەن تەمىنلەش",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "بۇ پروگرامما سىرتقى سىستېمىلار ھېسابات ، گۇرۇپپا ۋە ئەپلەرنى باشقۇرۇشتا ئىشلىتىدىغان بىر يۈرۈش API لارنى قوزغىتىدۇ.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "بۇ پروگرامما سىرتقى سىستېمىلار ھېسابات قۇرۇش ، تەھرىرلەش ، ئۆچۈرۈش ۋە سۈرۈشتۈرۈش ئۈچۈن ئىشلىتىدىغان بىر يۈرۈش API لارنى قوزغىتىدۇ\n\t\tخاسلىق ، سۈرۈشتۈرۈش ، گۇرۇپپىلارنى تەڭشەش ۋە ئۆچۈرۈش ، Nextcloud دا ئىشلىتىلىدىغان نورما ۋە سوئال ئومۇمىي ساقلاش. گۇرۇپپا باشقۇرۇش ھېساباتى\n\t\tNextcloud دىن سوئال سوراپ ، ئۇلار باشقۇرىدىغان گۇرۇپپىلارنىڭ باشقۇرغۇچىسى بىلەن ئوخشاش ئىقتىدارلارنى ئىشلىتەلەيدۇ. API يەنە قوزغىتىدۇ\n\t\tئاكتىپ Nextcloud قوللىنىشچان پروگراممىلىرى ، قوللىنىشچان ئۇچۇرلار ۋە ئەپنى يىراقتىن قوزغىتىش ياكى چەكلەش ئۈچۈن باشقۇرغۇچى.\n\t\tبۇ دېتال قوزغىتىلغاندىن كېيىن ، HTTP تەلەپلىرىنى Basic Auth ماۋزۇسى ئارقىلىق ھەر قانداق ئىقتىدارنى ئورۇندىغىلى بولىدۇ\n\t\tيۇقىرىدا كۆرسىتىلگەن. تەمىنلىگۈچى API ھۆججىتىدە تېخىمۇ كۆپ ئۇچۇرلار بار ، مەسىلەن تېلېفون چاقىرىش\n\t\tۋە مۇلازىمېتىرنىڭ ئىنكاسى."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/uk.js b/apps/provisioning_api/l10n/uk.js
new file mode 100644
index 00000000000..11c218eea89
--- /dev/null
+++ b/apps/provisioning_api/l10n/uk.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Обліковий запису, з яким ви увійшли, має бути адміністративним або дозволи редагування цих налаштувань.",
+ "Could not create non-existing user ID" : "Неможливо створити неіснуючого користувача ID",
+ "User already exists" : "Користувач вже існує",
+ "Group %1$s does not exist" : "Група %1$s не існує",
+ "Insufficient privileges for group %1$s" : "Недостатні дозволи для групи %1$s",
+ "No group specified (required for sub-admins)" : "Жодної групи не зазначено (потрібно для другорядних адміністраторів)",
+ "Sub-admin group does not exist" : "Група другорядних адміністраторів не існує",
+ "Cannot create sub-admins for admin group" : "Неможливо створити другорядних адміністраторів для групи адміністраторів",
+ "No permissions to promote sub-admins" : "Відсутні дозволи для збільшення повноважень другорядних адміністраторів",
+ "Invalid password value" : "Недійсне значення паролю",
+ "An email address is required, to send a password link to the user." : "Для надсилання посилання на пароль користувачеві необхідна адреса електронної пошти.",
+ "Required email address was not provided" : "Не зазначено обов'язкової ел. адреси",
+ "User creation failed" : "Не вдалося створити користувача",
+ "Invalid quota value: %1$s" : "Недійсне значення квоти: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Недійсне значення квоти: %1$s перебільшує максимальну квоту",
+ "Unlimited quota is forbidden on this instance" : "Необмежену квоту заборонено на цьому примірнику",
+ "Setting the password is not supported by the users backend" : "Встановлення паролю не підтримується бекендом користувача",
+ "Invalid language" : "Недійсний вибір мови",
+ "Invalid locale" : "Недійсний вибір локалі",
+ "Invalid first day of week" : "Недійсний перший день тижня",
+ "Cannot remove yourself from the admin group" : "Неможливо вилучити себе із групи адміністраторів",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Неможливо вилучити себе із цієї групи, оскільки ви є другорядним адміністратором",
+ "Not viable to remove user from the last group you are sub-admin of" : "Неможливо вилучити користувача з останньої групи, в якій ви є другорядним адміністратором",
+ "User does not exist" : "Користувач не існує",
+ "Group does not exist" : "Група не існує",
+ "User is not a sub-admin of this group" : "Користувач не є другорядним адміністратором цієї групи",
+ "Email address not available" : "Ел. адреса недоступна",
+ "Sending email failed" : "Не вдалося надіслати ел. лист",
+ "Email confirmation" : "Підтвердження електронною поштою",
+ "To enable the email address %s please click the button below." : "Щоб увімкнути адресу електронної пошти %s, натисніть кнопку нижче.",
+ "Confirm" : "Підтвердити",
+ "Email was already removed from account and cannot be confirmed anymore." : "Електронну адресу вже видалено з облікового запису, і її більше неможливо підтвердити.",
+ "Could not verify mail because the token is expired." : "Не вдалося перевірити пошту, оскільки термін дії токена минув.",
+ "Could not verify mail because the token is invalid." : "Не вдалося перевірити пошту, оскільки токен не дійсний.",
+ "An unexpected error occurred. Please contact your admin." : "Сталася неочікувана помилка. Будь ласка, зверніться до свого адміністратора.",
+ "Email confirmation successful" : "Підтвердження електронною поштою успішно",
+ "Provisioning API" : "API надання",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Цей застосунок надає доступ до набору API, які можуть використовувати стоонні системи для керування обліковими записами, групами та застосунками.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Цей застосунок підтримує набір API, які зовнішні системи можуть використовувати для створення, редагування, видалення та запитів користувача атрибути, запит, встановлення та видалення груп, встановлення квоти та запит загального обсягу пам’яті, що використовується в Nextcloud. Адміністратори групи користувачів також можуть надсилати запити Nextcloud і виконувати ті самі функції, що й адміністратори, для груп, якими вони керують. API також дозволяє адміністраторам надсилати запити до активних застосунків Nextcloud, отримувати інформацію про застосунок та віддалено вмикати чи вимикати застосунок. Після увімкнення застосунку HTTP-запити можна використовувати через заголовок Basic Auth для виконання будь-яких функцій, які перераховано вище. Додаткову інформацію можна знайти в документації Provisioning API включно з прикладами викликів та відповідей сервера."
+},
+"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);");
diff --git a/apps/provisioning_api/l10n/uk.json b/apps/provisioning_api/l10n/uk.json
new file mode 100644
index 00000000000..09884faa2e7
--- /dev/null
+++ b/apps/provisioning_api/l10n/uk.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "Обліковий запису, з яким ви увійшли, має бути адміністративним або дозволи редагування цих налаштувань.",
+ "Could not create non-existing user ID" : "Неможливо створити неіснуючого користувача ID",
+ "User already exists" : "Користувач вже існує",
+ "Group %1$s does not exist" : "Група %1$s не існує",
+ "Insufficient privileges for group %1$s" : "Недостатні дозволи для групи %1$s",
+ "No group specified (required for sub-admins)" : "Жодної групи не зазначено (потрібно для другорядних адміністраторів)",
+ "Sub-admin group does not exist" : "Група другорядних адміністраторів не існує",
+ "Cannot create sub-admins for admin group" : "Неможливо створити другорядних адміністраторів для групи адміністраторів",
+ "No permissions to promote sub-admins" : "Відсутні дозволи для збільшення повноважень другорядних адміністраторів",
+ "Invalid password value" : "Недійсне значення паролю",
+ "An email address is required, to send a password link to the user." : "Для надсилання посилання на пароль користувачеві необхідна адреса електронної пошти.",
+ "Required email address was not provided" : "Не зазначено обов'язкової ел. адреси",
+ "User creation failed" : "Не вдалося створити користувача",
+ "Invalid quota value: %1$s" : "Недійсне значення квоти: %1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "Недійсне значення квоти: %1$s перебільшує максимальну квоту",
+ "Unlimited quota is forbidden on this instance" : "Необмежену квоту заборонено на цьому примірнику",
+ "Setting the password is not supported by the users backend" : "Встановлення паролю не підтримується бекендом користувача",
+ "Invalid language" : "Недійсний вибір мови",
+ "Invalid locale" : "Недійсний вибір локалі",
+ "Invalid first day of week" : "Недійсний перший день тижня",
+ "Cannot remove yourself from the admin group" : "Неможливо вилучити себе із групи адміністраторів",
+ "Cannot remove yourself from this group as you are a sub-admin" : "Неможливо вилучити себе із цієї групи, оскільки ви є другорядним адміністратором",
+ "Not viable to remove user from the last group you are sub-admin of" : "Неможливо вилучити користувача з останньої групи, в якій ви є другорядним адміністратором",
+ "User does not exist" : "Користувач не існує",
+ "Group does not exist" : "Група не існує",
+ "User is not a sub-admin of this group" : "Користувач не є другорядним адміністратором цієї групи",
+ "Email address not available" : "Ел. адреса недоступна",
+ "Sending email failed" : "Не вдалося надіслати ел. лист",
+ "Email confirmation" : "Підтвердження електронною поштою",
+ "To enable the email address %s please click the button below." : "Щоб увімкнути адресу електронної пошти %s, натисніть кнопку нижче.",
+ "Confirm" : "Підтвердити",
+ "Email was already removed from account and cannot be confirmed anymore." : "Електронну адресу вже видалено з облікового запису, і її більше неможливо підтвердити.",
+ "Could not verify mail because the token is expired." : "Не вдалося перевірити пошту, оскільки термін дії токена минув.",
+ "Could not verify mail because the token is invalid." : "Не вдалося перевірити пошту, оскільки токен не дійсний.",
+ "An unexpected error occurred. Please contact your admin." : "Сталася неочікувана помилка. Будь ласка, зверніться до свого адміністратора.",
+ "Email confirmation successful" : "Підтвердження електронною поштою успішно",
+ "Provisioning API" : "API надання",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "Цей застосунок надає доступ до набору API, які можуть використовувати стоонні системи для керування обліковими записами, групами та застосунками.",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "Цей застосунок підтримує набір API, які зовнішні системи можуть використовувати для створення, редагування, видалення та запитів користувача атрибути, запит, встановлення та видалення груп, встановлення квоти та запит загального обсягу пам’яті, що використовується в Nextcloud. Адміністратори групи користувачів також можуть надсилати запити Nextcloud і виконувати ті самі функції, що й адміністратори, для груп, якими вони керують. API також дозволяє адміністраторам надсилати запити до активних застосунків Nextcloud, отримувати інформацію про застосунок та віддалено вмикати чи вимикати застосунок. Після увімкнення застосунку HTTP-запити можна використовувати через заголовок Basic Auth для виконання будь-яких функцій, які перераховано вище. Додаткову інформацію можна знайти в документації Provisioning API включно з прикладами викликів та відповідей сервера."
+},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/zh_CN.js b/apps/provisioning_api/l10n/zh_CN.js
new file mode 100644
index 00000000000..2bb24cb01ae
--- /dev/null
+++ b/apps/provisioning_api/l10n/zh_CN.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "登录的账号必须是管理员或有权编辑此设置。",
+ "Could not create non-existing user ID" : "无法创建不存在的用户 ID",
+ "User already exists" : "用户已存在",
+ "Group %1$s does not exist" : "组 %1$s 不存在",
+ "Insufficient privileges for group %1$s" : "组 %1$s 的权限不足",
+ "No group specified (required for sub-admins)" : "未指定组(子管理员需要)",
+ "Sub-admin group does not exist" : "子管理员组不存在",
+ "Cannot create sub-admins for admin group" : "无法为管理员组创建子管理员",
+ "No permissions to promote sub-admins" : "没有提升子管理员的权限",
+ "Invalid password value" : "密码值无效",
+ "An email address is required, to send a password link to the user." : "需要电子邮件地址,以将密码链接发送给用户。",
+ "Required email address was not provided" : "未提供所需的电子邮件地址",
+ "User creation failed" : "用户创建失败",
+ "Invalid quota value: %1$s" : "配额值无效:%1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "配额值无效。%1$s 超过了最大配额",
+ "Unlimited quota is forbidden on this instance" : "此实例上禁止无限配额",
+ "Setting the password is not supported by the users backend" : "用户后端不支持设置密码",
+ "Invalid language" : "语言无效",
+ "Invalid locale" : "区域设置无效",
+ "Invalid first day of week" : "一周的第一天无效",
+ "Cannot remove yourself from the admin group" : "无法将自己从管理员组中移除",
+ "Cannot remove yourself from this group as you are a sub-admin" : "无法将自己从此组中移除,因为您是子管理员",
+ "Not viable to remove user from the last group you are sub-admin of" : "无法从您作为子管理员的最后一个组中移除用户",
+ "User does not exist" : "用户不存在",
+ "Group does not exist" : "组不存在",
+ "User is not a sub-admin of this group" : "用户不是此组的子管理员",
+ "Email address not available" : "电子邮件地址不可用",
+ "Sending email failed" : "发送电子邮件失败",
+ "Email confirmation" : "电子邮件确认",
+ "To enable the email address %s please click the button below." : "要启用电子邮件地址 %s 请点击下方按钮。",
+ "Confirm" : "确认",
+ "Email was already removed from account and cannot be confirmed anymore." : "电子邮件已从帐户中删除,无法再确认。",
+ "Could not verify mail because the token is expired." : "无法验证邮件,因为令牌已过期",
+ "Could not verify mail because the token is invalid." : "无法验证邮件,因为令牌无效",
+ "An unexpected error occurred. Please contact your admin." : "发生意外错误。请联系系统管理员",
+ "Email confirmation successful" : "电子邮件确认成功",
+ "Provisioning API" : "供应 API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "此应用程序启用了一组 API,外部系统可以使用这些 API 来管理账号、组和应用。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "此应用程序启用了一组 API,外部系统可以使用这些 API 创建、编辑、删除和查询账号\n\t\t属性,查询、设置和移除组,设置配额和查询 Nextcloud 中使用的总存储量。组管理员账号\n\t\t还可以查询 Nextcloud,并为其管理的组执行与管理员相同的功能。API 还允许\n\t\t管理员查询活动的 Nextcloud 应用程序、应用程序信息,并远程启用或禁用应用程序。\n\t\t启用了应用程序后,可以通过基本身份验证标头使用 HTTP 请求来执行\n\t\t上方列出的任何功能。更多信息,可在供应 API 文档中获得,包括示例调用\n\t\t和服务器响应。"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/provisioning_api/l10n/zh_CN.json b/apps/provisioning_api/l10n/zh_CN.json
new file mode 100644
index 00000000000..03efc200979
--- /dev/null
+++ b/apps/provisioning_api/l10n/zh_CN.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "登录的账号必须是管理员或有权编辑此设置。",
+ "Could not create non-existing user ID" : "无法创建不存在的用户 ID",
+ "User already exists" : "用户已存在",
+ "Group %1$s does not exist" : "组 %1$s 不存在",
+ "Insufficient privileges for group %1$s" : "组 %1$s 的权限不足",
+ "No group specified (required for sub-admins)" : "未指定组(子管理员需要)",
+ "Sub-admin group does not exist" : "子管理员组不存在",
+ "Cannot create sub-admins for admin group" : "无法为管理员组创建子管理员",
+ "No permissions to promote sub-admins" : "没有提升子管理员的权限",
+ "Invalid password value" : "密码值无效",
+ "An email address is required, to send a password link to the user." : "需要电子邮件地址,以将密码链接发送给用户。",
+ "Required email address was not provided" : "未提供所需的电子邮件地址",
+ "User creation failed" : "用户创建失败",
+ "Invalid quota value: %1$s" : "配额值无效:%1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "配额值无效。%1$s 超过了最大配额",
+ "Unlimited quota is forbidden on this instance" : "此实例上禁止无限配额",
+ "Setting the password is not supported by the users backend" : "用户后端不支持设置密码",
+ "Invalid language" : "语言无效",
+ "Invalid locale" : "区域设置无效",
+ "Invalid first day of week" : "一周的第一天无效",
+ "Cannot remove yourself from the admin group" : "无法将自己从管理员组中移除",
+ "Cannot remove yourself from this group as you are a sub-admin" : "无法将自己从此组中移除,因为您是子管理员",
+ "Not viable to remove user from the last group you are sub-admin of" : "无法从您作为子管理员的最后一个组中移除用户",
+ "User does not exist" : "用户不存在",
+ "Group does not exist" : "组不存在",
+ "User is not a sub-admin of this group" : "用户不是此组的子管理员",
+ "Email address not available" : "电子邮件地址不可用",
+ "Sending email failed" : "发送电子邮件失败",
+ "Email confirmation" : "电子邮件确认",
+ "To enable the email address %s please click the button below." : "要启用电子邮件地址 %s 请点击下方按钮。",
+ "Confirm" : "确认",
+ "Email was already removed from account and cannot be confirmed anymore." : "电子邮件已从帐户中删除,无法再确认。",
+ "Could not verify mail because the token is expired." : "无法验证邮件,因为令牌已过期",
+ "Could not verify mail because the token is invalid." : "无法验证邮件,因为令牌无效",
+ "An unexpected error occurred. Please contact your admin." : "发生意外错误。请联系系统管理员",
+ "Email confirmation successful" : "电子邮件确认成功",
+ "Provisioning API" : "供应 API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "此应用程序启用了一组 API,外部系统可以使用这些 API 来管理账号、组和应用。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "此应用程序启用了一组 API,外部系统可以使用这些 API 创建、编辑、删除和查询账号\n\t\t属性,查询、设置和移除组,设置配额和查询 Nextcloud 中使用的总存储量。组管理员账号\n\t\t还可以查询 Nextcloud,并为其管理的组执行与管理员相同的功能。API 还允许\n\t\t管理员查询活动的 Nextcloud 应用程序、应用程序信息,并远程启用或禁用应用程序。\n\t\t启用了应用程序后,可以通过基本身份验证标头使用 HTTP 请求来执行\n\t\t上方列出的任何功能。更多信息,可在供应 API 文档中获得,包括示例调用\n\t\t和服务器响应。"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/zh_HK.js b/apps/provisioning_api/l10n/zh_HK.js
new file mode 100644
index 00000000000..50e0bd73c4a
--- /dev/null
+++ b/apps/provisioning_api/l10n/zh_HK.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "登錄帳戶必須是管理員或有編輯此設置的授權。",
+ "Could not create non-existing user ID" : "無法建立不存在的用戶 ID",
+ "User already exists" : "用戶已存在",
+ "Group %1$s does not exist" : "群組 %1$s 不存在",
+ "Insufficient privileges for group %1$s" : "群組 %1$s 權限不足",
+ "No group specified (required for sub-admins)" : "未指定群組(子管理員需要)",
+ "Sub-admin group does not exist" : "子管理員群組不存在",
+ "Cannot create sub-admins for admin group" : "無法為管理員群組建立子管理員",
+ "No permissions to promote sub-admins" : "沒有新增子管理員的權限",
+ "Invalid password value" : "無效的密碼值",
+ "An email address is required, to send a password link to the user." : "需要提供電郵地址,以便向用戶發送密碼鏈接。",
+ "Required email address was not provided" : "未提供必要的電郵地址",
+ "User creation failed" : "用戶建立失敗",
+ "Invalid quota value: %1$s" : "無效的空間限額值:%1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "無效的空間限額值。%1$s 超過了最大空間限額",
+ "Unlimited quota is forbidden on this instance" : "此實例禁止無限空間限額",
+ "Setting the password is not supported by the users backend" : "用戶後端系統不支援設定密碼",
+ "Invalid language" : "無效的語言",
+ "Invalid locale" : "無效的地區設定",
+ "Invalid first day of week" : "無效的一星期的第一天",
+ "Cannot remove yourself from the admin group" : "無法將您自己從管理員群組移除",
+ "Cannot remove yourself from this group as you are a sub-admin" : "因為您是子管理員,因此無法將自己從該群組中移除",
+ "Not viable to remove user from the last group you are sub-admin of" : "無法從您作為子管理員的最後一個群組中移除使用者",
+ "User does not exist" : "使用者不存在",
+ "Group does not exist" : "群組不存在",
+ "User is not a sub-admin of this group" : "用戶不是該群組的子管理員",
+ "Email address not available" : "電郵地址不可用",
+ "Sending email failed" : "傳送電子郵件失敗",
+ "Email confirmation" : "電郵地址確認",
+ "To enable the email address %s please click the button below." : "請單擊下面的按鈕以啟用電郵地址 %s。",
+ "Confirm" : "確認",
+ "Email was already removed from account and cannot be confirmed anymore." : "電郵地址已從帳戶中刪除,無法再確認。",
+ "Could not verify mail because the token is expired." : "權杖已過期,無法驗證郵件。",
+ "Could not verify mail because the token is invalid." : "權杖無效,無法驗證郵件。",
+ "An unexpected error occurred. Please contact your admin." : "發生了一個意料之外的錯誤。 請聯絡您的系統管理員。",
+ "Email confirmation successful" : "成功確認電郵地址",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "此應用程序啟用了一組 API ,外部系統可以使用這些 API 來管理帳戶、組和應用程序。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "此應用程序啟用了一組 API,外部系統可以使用它們來創建、編輯、刪除和查詢帳戶\n\t\t屬性、查詢、設置和刪除群組,設置配額以及查詢 Nextcloud 中使用的總存儲量。群組管理員帳戶\n\t\t還可以查詢 Nextcloud,並為其管理的組執行與管理員相同的功能。該 API 還支持\n\t\t管理員查詢活動的 Nextcloud 應用程序、應用程序信息,以及遠程啟用或禁用應用程序。\n\t\t啟用該應用後,可以通過基本身分驗證標頭使用 HTTP 請求執行\n以上所列任何功能。Provisioning API 文檔中提供了更多信息,包括示例調用\n\t\t和伺服器響應。"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/provisioning_api/l10n/zh_HK.json b/apps/provisioning_api/l10n/zh_HK.json
new file mode 100644
index 00000000000..3ad90d8b398
--- /dev/null
+++ b/apps/provisioning_api/l10n/zh_HK.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "登錄帳戶必須是管理員或有編輯此設置的授權。",
+ "Could not create non-existing user ID" : "無法建立不存在的用戶 ID",
+ "User already exists" : "用戶已存在",
+ "Group %1$s does not exist" : "群組 %1$s 不存在",
+ "Insufficient privileges for group %1$s" : "群組 %1$s 權限不足",
+ "No group specified (required for sub-admins)" : "未指定群組(子管理員需要)",
+ "Sub-admin group does not exist" : "子管理員群組不存在",
+ "Cannot create sub-admins for admin group" : "無法為管理員群組建立子管理員",
+ "No permissions to promote sub-admins" : "沒有新增子管理員的權限",
+ "Invalid password value" : "無效的密碼值",
+ "An email address is required, to send a password link to the user." : "需要提供電郵地址,以便向用戶發送密碼鏈接。",
+ "Required email address was not provided" : "未提供必要的電郵地址",
+ "User creation failed" : "用戶建立失敗",
+ "Invalid quota value: %1$s" : "無效的空間限額值:%1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "無效的空間限額值。%1$s 超過了最大空間限額",
+ "Unlimited quota is forbidden on this instance" : "此實例禁止無限空間限額",
+ "Setting the password is not supported by the users backend" : "用戶後端系統不支援設定密碼",
+ "Invalid language" : "無效的語言",
+ "Invalid locale" : "無效的地區設定",
+ "Invalid first day of week" : "無效的一星期的第一天",
+ "Cannot remove yourself from the admin group" : "無法將您自己從管理員群組移除",
+ "Cannot remove yourself from this group as you are a sub-admin" : "因為您是子管理員,因此無法將自己從該群組中移除",
+ "Not viable to remove user from the last group you are sub-admin of" : "無法從您作為子管理員的最後一個群組中移除使用者",
+ "User does not exist" : "使用者不存在",
+ "Group does not exist" : "群組不存在",
+ "User is not a sub-admin of this group" : "用戶不是該群組的子管理員",
+ "Email address not available" : "電郵地址不可用",
+ "Sending email failed" : "傳送電子郵件失敗",
+ "Email confirmation" : "電郵地址確認",
+ "To enable the email address %s please click the button below." : "請單擊下面的按鈕以啟用電郵地址 %s。",
+ "Confirm" : "確認",
+ "Email was already removed from account and cannot be confirmed anymore." : "電郵地址已從帳戶中刪除,無法再確認。",
+ "Could not verify mail because the token is expired." : "權杖已過期,無法驗證郵件。",
+ "Could not verify mail because the token is invalid." : "權杖無效,無法驗證郵件。",
+ "An unexpected error occurred. Please contact your admin." : "發生了一個意料之外的錯誤。 請聯絡您的系統管理員。",
+ "Email confirmation successful" : "成功確認電郵地址",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "此應用程序啟用了一組 API ,外部系統可以使用這些 API 來管理帳戶、組和應用程序。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "此應用程序啟用了一組 API,外部系統可以使用它們來創建、編輯、刪除和查詢帳戶\n\t\t屬性、查詢、設置和刪除群組,設置配額以及查詢 Nextcloud 中使用的總存儲量。群組管理員帳戶\n\t\t還可以查詢 Nextcloud,並為其管理的組執行與管理員相同的功能。該 API 還支持\n\t\t管理員查詢活動的 Nextcloud 應用程序、應用程序信息,以及遠程啟用或禁用應用程序。\n\t\t啟用該應用後,可以通過基本身分驗證標頭使用 HTTP 請求執行\n以上所列任何功能。Provisioning API 文檔中提供了更多信息,包括示例調用\n\t\t和伺服器響應。"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/l10n/zh_TW.js b/apps/provisioning_api/l10n/zh_TW.js
new file mode 100644
index 00000000000..716e6e0ee44
--- /dev/null
+++ b/apps/provisioning_api/l10n/zh_TW.js
@@ -0,0 +1,44 @@
+OC.L10N.register(
+ "provisioning_api",
+ {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "登入的帳號必須為管理員或是有權編輯此設定的帳號。",
+ "Could not create non-existing user ID" : "無法建立不存在的使用者 ID",
+ "User already exists" : "使用者已存在",
+ "Group %1$s does not exist" : "群組 %1$s 不存在",
+ "Insufficient privileges for group %1$s" : "群組 %1$s 權限不足",
+ "No group specified (required for sub-admins)" : "未指定群組(子管理員需要)",
+ "Sub-admin group does not exist" : "子管理員群組不存在",
+ "Cannot create sub-admins for admin group" : "無法為管理員群組建立子管理員",
+ "No permissions to promote sub-admins" : "沒有新增子管理員的權限",
+ "Invalid password value" : "無效的密碼值",
+ "An email address is required, to send a password link to the user." : "電子郵件地址必填,用來寄送密碼連結給使用者。",
+ "Required email address was not provided" : "未提供必要的電子郵件地址",
+ "User creation failed" : "使用者建立失敗",
+ "Invalid quota value: %1$s" : "無效的空間限額值:%1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "無效的空間限額值。%1$s 超過了最大空間限額",
+ "Unlimited quota is forbidden on this instance" : "此站台禁止無限空間限額",
+ "Setting the password is not supported by the users backend" : "使用者後端不支援設定密碼",
+ "Invalid language" : "無效的語言",
+ "Invalid locale" : "無效的地區設定",
+ "Invalid first day of week" : "無效的一週第一天",
+ "Cannot remove yourself from the admin group" : "無法將您自己從管理員群組移除",
+ "Cannot remove yourself from this group as you are a sub-admin" : "因為您是子管理員,因此無法將自己從該群組中移除",
+ "Not viable to remove user from the last group you are sub-admin of" : "無法從您作為子管理員的最後一個群組中移除使用者",
+ "User does not exist" : "使用者不存在",
+ "Group does not exist" : "群組不存在",
+ "User is not a sub-admin of this group" : "使用者不是該群組的子管理員",
+ "Email address not available" : "電子郵件地址不可用",
+ "Sending email failed" : "傳送電子郵件失敗",
+ "Email confirmation" : "電子郵件確認",
+ "To enable the email address %s please click the button below." : "若要啟用電子郵件地址 %s,請點擊下方按鈕。",
+ "Confirm" : "確認",
+ "Email was already removed from account and cannot be confirmed anymore." : "電子郵件已從帳號移除,且無法再確認。",
+ "Could not verify mail because the token is expired." : "無法驗證郵件,因為代符已過期。",
+ "Could not verify mail because the token is invalid." : "無法驗證郵件,因為代符無效。",
+ "An unexpected error occurred. Please contact your admin." : "遇到非預期的錯誤。請聯絡您的管理員。",
+ "Email confirmation successful" : "電子郵件確認成功",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "此應用程式啟用了一組 API,外部系統可以使用其來管理帳號、群組與應用程式。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "此應用程式啟用了一組 API,外部系統可以使用其來建立、編輯、刪除與查詢帳號\n\t\t屬性,查詢、設定與移除群組,設定配額與查詢 Nextcloud 中使用的總儲存空間。群組管理員帳號\n\t\t也可以用其來查詢 Nextcloud,並在其管理的群組中執行與系統管理員相同的動作。這組 API 也讓\n\t\t管理員可以查詢作用中的 Nextcloud 應用程式、應用程式資訊,以及遠端啟用或停用應用程式。\n\t\t應用程式啟用後,可以使用基本驗證標頭來使用 HTTP 請求執行上面\n\t\t列出的任何功能。更多資訊在 Provisioning API 的文件中提供,包含範例呼叫\n\t\t與伺服器回應。"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/provisioning_api/l10n/zh_TW.json b/apps/provisioning_api/l10n/zh_TW.json
new file mode 100644
index 00000000000..e8b80a3f1d2
--- /dev/null
+++ b/apps/provisioning_api/l10n/zh_TW.json
@@ -0,0 +1,42 @@
+{ "translations": {
+ "Logged in account must be an administrator or have authorization to edit this setting." : "登入的帳號必須為管理員或是有權編輯此設定的帳號。",
+ "Could not create non-existing user ID" : "無法建立不存在的使用者 ID",
+ "User already exists" : "使用者已存在",
+ "Group %1$s does not exist" : "群組 %1$s 不存在",
+ "Insufficient privileges for group %1$s" : "群組 %1$s 權限不足",
+ "No group specified (required for sub-admins)" : "未指定群組(子管理員需要)",
+ "Sub-admin group does not exist" : "子管理員群組不存在",
+ "Cannot create sub-admins for admin group" : "無法為管理員群組建立子管理員",
+ "No permissions to promote sub-admins" : "沒有新增子管理員的權限",
+ "Invalid password value" : "無效的密碼值",
+ "An email address is required, to send a password link to the user." : "電子郵件地址必填,用來寄送密碼連結給使用者。",
+ "Required email address was not provided" : "未提供必要的電子郵件地址",
+ "User creation failed" : "使用者建立失敗",
+ "Invalid quota value: %1$s" : "無效的空間限額值:%1$s",
+ "Invalid quota value. %1$s is exceeding the maximum quota" : "無效的空間限額值。%1$s 超過了最大空間限額",
+ "Unlimited quota is forbidden on this instance" : "此站台禁止無限空間限額",
+ "Setting the password is not supported by the users backend" : "使用者後端不支援設定密碼",
+ "Invalid language" : "無效的語言",
+ "Invalid locale" : "無效的地區設定",
+ "Invalid first day of week" : "無效的一週第一天",
+ "Cannot remove yourself from the admin group" : "無法將您自己從管理員群組移除",
+ "Cannot remove yourself from this group as you are a sub-admin" : "因為您是子管理員,因此無法將自己從該群組中移除",
+ "Not viable to remove user from the last group you are sub-admin of" : "無法從您作為子管理員的最後一個群組中移除使用者",
+ "User does not exist" : "使用者不存在",
+ "Group does not exist" : "群組不存在",
+ "User is not a sub-admin of this group" : "使用者不是該群組的子管理員",
+ "Email address not available" : "電子郵件地址不可用",
+ "Sending email failed" : "傳送電子郵件失敗",
+ "Email confirmation" : "電子郵件確認",
+ "To enable the email address %s please click the button below." : "若要啟用電子郵件地址 %s,請點擊下方按鈕。",
+ "Confirm" : "確認",
+ "Email was already removed from account and cannot be confirmed anymore." : "電子郵件已從帳號移除,且無法再確認。",
+ "Could not verify mail because the token is expired." : "無法驗證郵件,因為代符已過期。",
+ "Could not verify mail because the token is invalid." : "無法驗證郵件,因為代符無效。",
+ "An unexpected error occurred. Please contact your admin." : "遇到非預期的錯誤。請聯絡您的管理員。",
+ "Email confirmation successful" : "電子郵件確認成功",
+ "Provisioning API" : "Provisioning API",
+ "This application enables a set of APIs that external systems can use to manage accounts, groups and apps." : "此應用程式啟用了一組 API,外部系統可以使用其來管理帳號、群組與應用程式。",
+ "This application enables a set of APIs that external systems can use to create, edit, delete and query account\n\t\tattributes, query, set and remove groups, set quota and query total storage used in Nextcloud. Group admin accounts\n\t\tcan also query Nextcloud and perform the same functions as an admin for groups they manage. The API also enables\n\t\tan admin to query for active Nextcloud applications, application info, and to enable or disable an app remotely.\n\t\tOnce the app is enabled, HTTP requests can be used via a Basic Auth header to perform any of the functions\n\t\tlisted above. More information is available in the Provisioning API documentation, including example calls\n\t\tand server responses." : "此應用程式啟用了一組 API,外部系統可以使用其來建立、編輯、刪除與查詢帳號\n\t\t屬性,查詢、設定與移除群組,設定配額與查詢 Nextcloud 中使用的總儲存空間。群組管理員帳號\n\t\t也可以用其來查詢 Nextcloud,並在其管理的群組中執行與系統管理員相同的動作。這組 API 也讓\n\t\t管理員可以查詢作用中的 Nextcloud 應用程式、應用程式資訊,以及遠端啟用或停用應用程式。\n\t\t應用程式啟用後,可以使用基本驗證標頭來使用 HTTP 請求執行上面\n\t\t列出的任何功能。更多資訊在 Provisioning API 的文件中提供,包含範例呼叫\n\t\t與伺服器回應。"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/provisioning_api/lib/AppInfo/Application.php b/apps/provisioning_api/lib/AppInfo/Application.php
index b7a93d6fb13..57de9dad416 100644
--- a/apps/provisioning_api/lib/AppInfo/Application.php
+++ b/apps/provisioning_api/lib/AppInfo/Application.php
@@ -1,67 +1,79 @@
<?php
+
/**
- *
- *
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Provisioning_API\AppInfo;
-use OC\AppFramework\Utility\SimpleContainer;
-use OC\AppFramework\Utility\TimeFactory;
-use OC\Settings\Mailer\NewUserMailHelper;
+use OC\Group\Manager as GroupManager;
+use OCA\Provisioning_API\Capabilities;
+use OCA\Provisioning_API\Listener\UserDeletedListener;
use OCA\Provisioning_API\Middleware\ProvisioningApiMiddleware;
+use OCA\Settings\Mailer\NewUserMailHelper;
use OCP\AppFramework\App;
+use OCP\AppFramework\Bootstrap\IBootContext;
+use OCP\AppFramework\Bootstrap\IBootstrap;
+use OCP\AppFramework\Bootstrap\IRegistrationContext;
+use OCP\AppFramework\Utility\IControllerMethodReflector;
+use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Defaults;
+use OCP\IConfig;
+use OCP\IGroupManager;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\L10N\IFactory;
+use OCP\Mail\IMailer;
+use OCP\Security\ICrypto;
+use OCP\Security\ISecureRandom;
+use OCP\User\Events\UserDeletedEvent;
use OCP\Util;
+use Psr\Container\ContainerInterface;
-class Application extends App {
- public function __construct(array $urlParams = array()) {
+class Application extends App implements IBootstrap {
+ public function __construct(array $urlParams = []) {
parent::__construct('provisioning_api', $urlParams);
+ }
- $container = $this->getContainer();
- $server = $container->getServer();
+ public function register(IRegistrationContext $context): void {
+ $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
- $container->registerService(NewUserMailHelper::class, function(SimpleContainer $c) use ($server) {
+ $context->registerService(NewUserMailHelper::class, function (ContainerInterface $c) {
return new NewUserMailHelper(
- $server->query(Defaults::class),
- $server->getURLGenerator(),
- $server->getL10N('settings'),
- $server->getMailer(),
- $server->getSecureRandom(),
- new TimeFactory(),
- $server->getConfig(),
- $server->getCrypto(),
+ $c->get(Defaults::class),
+ $c->get(IURLGenerator::class),
+ $c->get(IFactory::class),
+ $c->get(IMailer::class),
+ $c->get(ISecureRandom::class),
+ $c->get(ITimeFactory::class),
+ $c->get(IConfig::class),
+ $c->get(ICrypto::class),
Util::getDefaultEmailAddress('no-reply')
);
});
- $container->registerService('ProvisioningApiMiddleware', function(SimpleContainer $c) use ($server) {
- $user = $server->getUserManager()->get($c['UserId']);
- $isAdmin = $user !== null ? $server->getGroupManager()->isAdmin($user->getUID()) : false;
- $isSubAdmin = $user !== null ? $server->getGroupManager()->getSubAdmin()->isSubAdmin($user) : false;
+ $context->registerService(ProvisioningApiMiddleware::class, function (ContainerInterface $c) {
+ $user = $c->get(IUserManager::class)->get($c->get('UserId'));
+ $isAdmin = false;
+ $isSubAdmin = false;
+
+ if ($user instanceof IUser) {
+ $groupManager = $c->get(IGroupManager::class);
+ assert($groupManager instanceof GroupManager);
+ $isAdmin = $groupManager->isAdmin($user->getUID());
+ $isSubAdmin = $groupManager->getSubAdmin()->isSubAdmin($user);
+ }
+
return new ProvisioningApiMiddleware(
- $c['ControllerMethodReflector'],
+ $c->get(IControllerMethodReflector::class),
$isAdmin,
$isSubAdmin
);
});
- $container->registerMiddleWare('ProvisioningApiMiddleware');
+ $context->registerMiddleware(ProvisioningApiMiddleware::class);
+ $context->registerCapability(Capabilities::class);
+ }
+
+ public function boot(IBootContext $context): void {
}
}
diff --git a/apps/provisioning_api/lib/Capabilities.php b/apps/provisioning_api/lib/Capabilities.php
new file mode 100644
index 00000000000..5becf6f611f
--- /dev/null
+++ b/apps/provisioning_api/lib/Capabilities.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Provisioning_API;
+
+use OCA\FederatedFileSharing\FederatedShareProvider;
+use OCP\App\IAppManager;
+use OCP\Capabilities\ICapability;
+use OCP\Server;
+
+class Capabilities implements ICapability {
+
+ public function __construct(
+ private IAppManager $appManager,
+ ) {
+ }
+
+ /**
+ * Function an app uses to return the capabilities
+ *
+ * @return array{
+ * provisioning_api: array{
+ * version: string,
+ * AccountPropertyScopesVersion: int,
+ * AccountPropertyScopesFederatedEnabled: bool,
+ * AccountPropertyScopesPublishedEnabled: bool,
+ * },
+ * }
+ */
+ public function getCapabilities() {
+ $federatedScopeEnabled = $this->appManager->isEnabledForUser('federation');
+
+ $publishedScopeEnabled = false;
+
+ $federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
+ if ($federatedFileSharingEnabled) {
+ /** @var FederatedShareProvider $shareProvider */
+ $shareProvider = Server::get(FederatedShareProvider::class);
+ $publishedScopeEnabled = $shareProvider->isLookupServerUploadEnabled();
+ }
+
+ return [
+ 'provisioning_api' => [
+ 'version' => $this->appManager->getAppVersion('provisioning_api'),
+ 'AccountPropertyScopesVersion' => 2,
+ 'AccountPropertyScopesFederatedEnabled' => $federatedScopeEnabled,
+ 'AccountPropertyScopesPublishedEnabled' => $publishedScopeEnabled,
+ ]
+ ];
+ }
+}
diff --git a/apps/provisioning_api/lib/Controller/AUserDataOCSController.php b/apps/provisioning_api/lib/Controller/AUserDataOCSController.php
new file mode 100644
index 00000000000..d321adf7c8f
--- /dev/null
+++ b/apps/provisioning_api/lib/Controller/AUserDataOCSController.php
@@ -0,0 +1,325 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Provisioning_API\Controller;
+
+use OC\Group\Manager as GroupManager;
+use OC\User\Backend;
+use OC\User\NoUserException;
+use OCA\Provisioning_API\ResponseDefinitions;
+use OCP\Accounts\IAccountManager;
+use OCP\Accounts\PropertyDoesNotExistException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\AppFramework\OCS\OCSNotFoundException;
+use OCP\AppFramework\OCSController;
+use OCP\Files\FileInfo;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Group\ISubAdmin;
+use OCP\IConfig;
+use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use OCP\L10N\IFactory;
+use OCP\Server;
+use OCP\User\Backend\ISetDisplayNameBackend;
+use OCP\User\Backend\ISetPasswordBackend;
+use OCP\Util;
+
+/**
+ * @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
+ * @psalm-import-type Provisioning_APIUserDetailsQuota from ResponseDefinitions
+ */
+abstract class AUserDataOCSController extends OCSController {
+ public const SCOPE_SUFFIX = 'Scope';
+
+ public const USER_FIELD_DISPLAYNAME = 'display';
+ public const USER_FIELD_LANGUAGE = 'language';
+ public const USER_FIELD_LOCALE = 'locale';
+ public const USER_FIELD_FIRST_DAY_OF_WEEK = 'first_day_of_week';
+ public const USER_FIELD_PASSWORD = 'password';
+ public const USER_FIELD_QUOTA = 'quota';
+ public const USER_FIELD_MANAGER = 'manager';
+ public const USER_FIELD_NOTIFICATION_EMAIL = 'notify_email';
+
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ protected IUserManager $userManager,
+ protected IConfig $config,
+ protected GroupManager $groupManager,
+ protected IUserSession $userSession,
+ protected IAccountManager $accountManager,
+ protected ISubAdmin $subAdminManager,
+ protected IFactory $l10nFactory,
+ protected IRootFolder $rootFolder,
+ ) {
+ parent::__construct($appName, $request);
+ }
+
+ /**
+ * creates a array with all user data
+ *
+ * @param string $userId
+ * @param bool $includeScopes
+ * @return Provisioning_APIUserDetails|null
+ * @throws NotFoundException
+ * @throws OCSException
+ * @throws OCSNotFoundException
+ */
+ protected function getUserData(string $userId, bool $includeScopes = false): ?array {
+ $currentLoggedInUser = $this->userSession->getUser();
+ assert($currentLoggedInUser !== null, 'No user logged in');
+
+ $data = [];
+
+ // Check if the target user exists
+ $targetUserObject = $this->userManager->get($userId);
+ if ($targetUserObject === null) {
+ throw new OCSNotFoundException('User does not exist');
+ }
+
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if ($isAdmin
+ || $isDelegatedAdmin
+ || $this->groupManager->getSubAdmin()->isUserAccessible($currentLoggedInUser, $targetUserObject)) {
+ $data['enabled'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true';
+ } else {
+ // Check they are looking up themselves
+ if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
+ return null;
+ }
+ }
+
+ // Get groups data
+ $userAccount = $this->accountManager->getAccount($targetUserObject);
+ $groups = $this->groupManager->getUserGroups($targetUserObject);
+ $gids = [];
+ foreach ($groups as $group) {
+ $gids[] = $group->getGID();
+ }
+
+ if ($isAdmin || $isDelegatedAdmin) {
+ try {
+ # might be thrown by LDAP due to handling of users disappears
+ # from the external source (reasons unknown to us)
+ # cf. https://github.com/nextcloud/server/issues/12991
+ $data['storageLocation'] = $targetUserObject->getHome();
+ } catch (NoUserException $e) {
+ throw new OCSNotFoundException($e->getMessage(), $e);
+ }
+ }
+
+ // Find the data
+ $data['id'] = $targetUserObject->getUID();
+ $data['firstLoginTimestamp'] = $targetUserObject->getFirstLogin();
+ $data['lastLoginTimestamp'] = $targetUserObject->getLastLogin();
+ $data['lastLogin'] = $targetUserObject->getLastLogin() * 1000;
+ $data['backend'] = $targetUserObject->getBackendClassName();
+ $data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
+ $data[self::USER_FIELD_QUOTA] = $this->fillStorageInfo($targetUserObject);
+ $managers = $this->getManagers($targetUserObject);
+ $data[self::USER_FIELD_MANAGER] = empty($managers) ? '' : $managers[0];
+
+ try {
+ if ($includeScopes) {
+ $data[IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope();
+ }
+
+ $data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getSystemEMailAddress();
+ if ($includeScopes) {
+ $data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
+ }
+
+ $additionalEmails = $additionalEmailScopes = [];
+ $emailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
+ foreach ($emailCollection->getProperties() as $property) {
+ $email = mb_strtolower(trim($property->getValue()));
+ $additionalEmails[] = $email;
+ if ($includeScopes) {
+ $additionalEmailScopes[] = $property->getScope();
+ }
+ }
+ $data[IAccountManager::COLLECTION_EMAIL] = $additionalEmails;
+ if ($includeScopes) {
+ $data[IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX] = $additionalEmailScopes;
+ }
+
+ $data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
+ $data[IAccountManager::PROPERTY_DISPLAYNAME_LEGACY] = $data[IAccountManager::PROPERTY_DISPLAYNAME];
+ if ($includeScopes) {
+ $data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
+ }
+
+ foreach ([
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ] as $propertyName) {
+ $property = $userAccount->getProperty($propertyName);
+ $data[$propertyName] = $property->getValue();
+ if ($includeScopes) {
+ $data[$propertyName . self::SCOPE_SUFFIX] = $property->getScope();
+ }
+ }
+ } catch (PropertyDoesNotExistException $e) {
+ // hard coded properties should exist
+ throw new OCSException($e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR, $e);
+ }
+
+ $data['groups'] = $gids;
+ $data[self::USER_FIELD_LANGUAGE] = $this->l10nFactory->getUserLanguage($targetUserObject);
+ $data[self::USER_FIELD_LOCALE] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
+ $data[self::USER_FIELD_NOTIFICATION_EMAIL] = $targetUserObject->getPrimaryEMailAddress();
+
+ $backend = $targetUserObject->getBackend();
+ $data['backendCapabilities'] = [
+ 'setDisplayName' => $backend instanceof ISetDisplayNameBackend || $backend->implementsActions(Backend::SET_DISPLAYNAME),
+ 'setPassword' => $backend instanceof ISetPasswordBackend || $backend->implementsActions(Backend::SET_PASSWORD),
+ ];
+
+ return $data;
+ }
+
+ /**
+ * @return string[]
+ */
+ protected function getManagers(IUser $user): array {
+ $currentLoggedInUser = $this->userSession->getUser();
+
+ $managerUids = $user->getManagerUids();
+ if ($this->groupManager->isAdmin($currentLoggedInUser->getUID()) || $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())) {
+ return $managerUids;
+ }
+
+ if ($this->subAdminManager->isSubAdmin($currentLoggedInUser)) {
+ $accessibleManagerUids = array_values(array_filter(
+ $managerUids,
+ function (string $managerUid) use ($currentLoggedInUser) {
+ $manager = $this->userManager->get($managerUid);
+ if (!($manager instanceof IUser)) {
+ return false;
+ }
+ return $this->subAdminManager->isUserAccessible($currentLoggedInUser, $manager);
+ },
+ ));
+ return $accessibleManagerUids;
+ }
+
+ return [];
+ }
+
+ /**
+ * Get the groups a user is a subadmin of
+ *
+ * @param string $userId
+ * @return list<string>
+ * @throws OCSException
+ */
+ protected function getUserSubAdminGroupsData(string $userId): array {
+ $user = $this->userManager->get($userId);
+ // Check if the user exists
+ if ($user === null) {
+ throw new OCSNotFoundException('User does not exist');
+ }
+
+ // Get the subadmin groups
+ $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
+ $groups = [];
+ foreach ($subAdminGroups as $key => $group) {
+ $groups[] = $group->getGID();
+ }
+
+ return $groups;
+ }
+
+ /**
+ * @param IUser $user
+ * @return Provisioning_APIUserDetailsQuota
+ * @throws OCSException
+ */
+ protected function fillStorageInfo(IUser $user): array {
+ $includeExternal = $this->config->getSystemValueBool('quota_include_external_storage');
+ $userId = $user->getUID();
+
+ $quota = $user->getQuota();
+ if ($quota === 'none') {
+ $quota = FileInfo::SPACE_UNLIMITED;
+ } else {
+ $quota = Util::computerFileSize($quota);
+ if ($quota === false) {
+ $quota = FileInfo::SPACE_UNLIMITED;
+ }
+ }
+
+ try {
+ if ($includeExternal) {
+ \OC_Util::tearDownFS();
+ \OC_Util::setupFS($user->getUID());
+ $storage = \OC_Helper::getStorageInfo('/', null, true, false);
+ $data = [
+ 'free' => $storage['free'],
+ 'used' => $storage['used'],
+ 'total' => $storage['total'],
+ 'relative' => $storage['relative'],
+ self::USER_FIELD_QUOTA => $storage['quota'],
+ ];
+ } else {
+ $userFileInfo = $this->rootFolder->getUserFolder($userId)->getStorage()->getCache()->get('');
+ $used = $userFileInfo->getSize();
+
+ if ($quota > 0) {
+ // prevent division by zero or error codes (negative values)
+ $relative = round(($used / $quota) * 10000) / 100;
+ $free = $quota - $used;
+ $total = $quota;
+ } else {
+ $relative = 0;
+ $free = FileInfo::SPACE_UNLIMITED;
+ $total = FileInfo::SPACE_UNLIMITED;
+ }
+
+ $data = [
+ 'free' => $free,
+ 'used' => $used,
+ 'total' => $total,
+ 'relative' => $relative,
+ self::USER_FIELD_QUOTA => $quota,
+ ];
+ }
+ } catch (NotFoundException $ex) {
+ $data = [
+ self::USER_FIELD_QUOTA => $quota >= 0 ? $quota : 'none',
+ 'used' => 0
+ ];
+ } catch (\Exception $e) {
+ Server::get(\Psr\Log\LoggerInterface::class)->error(
+ 'Could not load storage info for {user}',
+ [
+ 'app' => 'provisioning_api',
+ 'user' => $userId,
+ 'exception' => $e,
+ ]
+ );
+ return [];
+ }
+ return $data;
+ }
+}
diff --git a/apps/provisioning_api/lib/Controller/AppConfigController.php b/apps/provisioning_api/lib/Controller/AppConfigController.php
index 0ca5e4e20a1..d8af1f38d95 100644
--- a/apps/provisioning_api/lib/Controller/AppConfigController.php
+++ b/apps/provisioning_api/lib/Controller/AppConfigController.php
@@ -1,143 +1,182 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2016 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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\Provisioning_API\Controller;
-
+use OC\AppConfig;
+use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
+use OCP\App\IAppManager;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
+use OCP\Exceptions\AppConfigUnknownKeyException;
use OCP\IAppConfig;
-use OCP\IConfig;
+use OCP\IGroupManager;
+use OCP\IL10N;
use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Settings\IDelegatedSettings;
+use OCP\Settings\IManager;
class AppConfigController extends OCSController {
-
- /** @var IConfig */
- protected $config;
-
- /** @var IAppConfig */
- protected $appConfig;
-
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IConfig $config
- * @param IAppConfig $appConfig
- */
- public function __construct($appName,
- IRequest $request,
- IConfig $config,
- IAppConfig $appConfig) {
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ /** @var AppConfig */
+ private IAppConfig $appConfig,
+ private IUserSession $userSession,
+ private IL10N $l10n,
+ private IGroupManager $groupManager,
+ private IManager $settingManager,
+ private IAppManager $appManager,
+ ) {
parent::__construct($appName, $request);
- $this->config = $config;
- $this->appConfig = $appConfig;
}
/**
- * @return DataResponse
+ * Get a list of apps
+ *
+ * @return DataResponse<Http::STATUS_OK, array{data: list<string>}, array{}>
+ *
+ * 200: Apps returned
*/
- public function getApps() {
+ public function getApps(): DataResponse {
return new DataResponse([
'data' => $this->appConfig->getApps(),
]);
}
/**
- * @param string $app
- * @return DataResponse
+ * Get the config keys of an app
+ *
+ * @param string $app ID of the app
+ * @return DataResponse<Http::STATUS_OK, array{data: list<string>}, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
+ *
+ * 200: Keys returned
+ * 403: App is not allowed
*/
- public function getKeys($app) {
+ public function getKeys(string $app): DataResponse {
try {
$this->verifyAppId($app);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
return new DataResponse([
- 'data' => $this->config->getAppKeys($app),
+ 'data' => $this->appConfig->getKeys($app),
]);
}
/**
- * @param string $app
- * @param string $key
- * @param string $defaultValue
- * @return DataResponse
+ * Get a the config value of an app
+ *
+ * @param string $app ID of the app
+ * @param string $key Key
+ * @param string $defaultValue Default returned value if the value is empty
+ * @return DataResponse<Http::STATUS_OK, array{data: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
+ *
+ * 200: Value returned
+ * 403: App is not allowed
*/
- public function getValue($app, $key, $defaultValue = '') {
+ public function getValue(string $app, string $key, string $defaultValue = ''): DataResponse {
try {
$this->verifyAppId($app);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
- return new DataResponse([
- 'data' => $this->config->getAppValue($app, $key, $defaultValue),
- ]);
+
+ /** @psalm-suppress InternalMethod */
+ $value = $this->appConfig->getValueMixed($app, $key, $defaultValue, null);
+ return new DataResponse(['data' => $value]);
}
/**
- * @PasswordConfirmationRequired
- * @param string $app
- * @param string $key
- * @param string $value
- * @return DataResponse
+ * @NoSubAdminRequired
+ *
+ * Update the config value of an app
+ *
+ * @param string $app ID of the app
+ * @param string $key Key to update
+ * @param string $value New value for the key
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
+ *
+ * 200: Value updated successfully
+ * 403: App or key is not allowed
*/
- public function setValue($app, $key, $value) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function setValue(string $app, string $key, string $value): DataResponse {
+ $user = $this->userSession->getUser();
+ if ($user === null) {
+ throw new \Exception('User is not logged in.'); // Should not happen, since method is guarded by middleware
+ }
+
+ if (!$this->isAllowedToChangedKey($user, $app, $key)) {
+ throw new NotAdminException($this->l10n->t('Logged in account must be an administrator or have authorization to edit this setting.'));
+ }
+
try {
$this->verifyAppId($app);
- $this->verifyConfigKey($app, $key);
+ $this->verifyConfigKey($app, $key, $value);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
- $this->config->setAppValue($app, $key, $value);
+ $type = null;
+ try {
+ $configDetails = $this->appConfig->getDetails($app, $key);
+ $type = $configDetails['type'];
+ } catch (AppConfigUnknownKeyException) {
+ }
+
+ /** @psalm-suppress InternalMethod */
+ match ($type) {
+ IAppConfig::VALUE_BOOL => $this->appConfig->setValueBool($app, $key, (bool)$value),
+ IAppConfig::VALUE_FLOAT => $this->appConfig->setValueFloat($app, $key, (float)$value),
+ IAppConfig::VALUE_INT => $this->appConfig->setValueInt($app, $key, (int)$value),
+ IAppConfig::VALUE_STRING => $this->appConfig->setValueString($app, $key, $value),
+ IAppConfig::VALUE_ARRAY => $this->appConfig->setValueArray($app, $key, \json_decode($value, true)),
+ default => $this->appConfig->setValueMixed($app, $key, $value),
+ };
+
return new DataResponse();
}
/**
- * @PasswordConfirmationRequired
- * @param string $app
- * @param string $key
- * @return DataResponse
+ * Delete a config key of an app
+ *
+ * @param string $app ID of the app
+ * @param string $key Key to delete
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
+ *
+ * 200: Key deleted successfully
+ * 403: App or key is not allowed
*/
- public function deleteKey($app, $key) {
+ #[PasswordConfirmationRequired]
+ public function deleteKey(string $app, string $key): DataResponse {
try {
$this->verifyAppId($app);
- $this->verifyConfigKey($app, $key);
+ $this->verifyConfigKey($app, $key, '');
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
- $this->config->deleteAppValue($app, $key);
+ $this->appConfig->deleteKey($app, $key);
return new DataResponse();
}
/**
- * @param string $app
* @throws \InvalidArgumentException
*/
- protected function verifyAppId($app) {
- if (\OC_App::cleanAppId($app) !== $app) {
+ protected function verifyAppId(string $app): void {
+ if ($this->appManager->cleanAppId($app) !== $app) {
throw new \InvalidArgumentException('Invalid app id given');
}
}
@@ -145,15 +184,53 @@ class AppConfigController extends OCSController {
/**
* @param string $app
* @param string $key
+ * @param string $value
* @throws \InvalidArgumentException
*/
- protected function verifyConfigKey($app, $key) {
+ protected function verifyConfigKey(string $app, string $key, string $value) {
if (in_array($key, ['installed_version', 'enabled', 'types'])) {
throw new \InvalidArgumentException('The given key can not be set');
}
+ if ($app === 'core' && $key === 'encryption_enabled' && $value !== 'yes') {
+ throw new \InvalidArgumentException('The given key can not be set');
+ }
+
if ($app === 'core' && (strpos($key, 'public_') === 0 || strpos($key, 'remote_') === 0)) {
throw new \InvalidArgumentException('The given key can not be set');
}
+
+ if ($app === 'files'
+ && $key === 'default_quota'
+ && $value === 'none'
+ && $this->appConfig->getValueInt('files', 'allow_unlimited_quota', 1) === 0) {
+ throw new \InvalidArgumentException('The given key can not be set, unlimited quota is forbidden on this instance');
+ }
+ }
+
+ private function isAllowedToChangedKey(IUser $user, string $app, string $key): bool {
+ // Admin right verification
+ $isAdmin = $this->groupManager->isAdmin($user->getUID());
+ if ($isAdmin) {
+ return true;
+ }
+
+ $settings = $this->settingManager->getAllAllowedAdminSettings($user);
+ foreach ($settings as $setting) {
+ if (!($setting instanceof IDelegatedSettings)) {
+ continue;
+ }
+ $allowedKeys = $setting->getAuthorizedAppConfig();
+ if (!array_key_exists($app, $allowedKeys)) {
+ continue;
+ }
+ foreach ($allowedKeys[$app] as $regex) {
+ if ($regex === $key
+ || (str_starts_with($regex, '/') && preg_match($regex, $key) === 1)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
}
diff --git a/apps/provisioning_api/lib/Controller/AppsController.php b/apps/provisioning_api/lib/Controller/AppsController.php
index 30062d94a44..3f6cff7442a 100644
--- a/apps/provisioning_api/lib/Controller/AppsController.php
+++ b/apps/provisioning_api/lib/Controller/AppsController.php
@@ -1,125 +1,153 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Provisioning_API\Controller;
-use \OC_App;
+use OC\App\AppStore\AppNotFoundException;
+use OC\Installer;
+use OC_App;
use OCP\App\AppPathNotFoundException;
use OCP\App\IAppManager;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCSController;
+use OCP\IAppConfig;
use OCP\IRequest;
class AppsController extends OCSController {
- /** @var \OCP\App\IAppManager */
- private $appManager;
-
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IAppManager $appManager
- */
public function __construct(
- $appName,
+ string $appName,
IRequest $request,
- IAppManager $appManager
+ private IAppManager $appManager,
+ private Installer $installer,
+ private IAppConfig $appConfig,
) {
parent::__construct($appName, $request);
+ }
- $this->appManager = $appManager;
+ /**
+ * @throws \InvalidArgumentException
+ */
+ protected function verifyAppId(string $app): string {
+ $cleanId = $this->appManager->cleanAppId($app);
+ if ($cleanId !== $app) {
+ throw new \InvalidArgumentException('Invalid app id given');
+ }
+ return $cleanId;
}
/**
- * @param string $filter
- * @return DataResponse
+ * Get a list of installed apps
+ *
+ * @param ?string $filter Filter for enabled or disabled apps
+ * @return DataResponse<Http::STATUS_OK, array{apps: list<string>}, array{}>
* @throws OCSException
+ *
+ * 200: Installed apps returned
*/
- public function getApps($filter = null) {
+ public function getApps(?string $filter = null): DataResponse {
$apps = (new OC_App())->listAllApps();
+ /** @var list<string> $list */
$list = [];
- foreach($apps as $app) {
+ foreach ($apps as $app) {
$list[] = $app['id'];
}
- if($filter){
- switch($filter){
+ if ($filter) {
+ switch ($filter) {
case 'enabled':
return new DataResponse(['apps' => \OC_App::getEnabledApps()]);
break;
case 'disabled':
$enabled = OC_App::getEnabledApps();
- return new DataResponse(['apps' => array_diff($list, $enabled)]);
+ return new DataResponse(['apps' => array_values(array_diff($list, $enabled))]);
break;
default:
// Invalid filter variable
throw new OCSException('', 101);
}
-
} else {
return new DataResponse(['apps' => $list]);
}
}
/**
- * @param string $app
- * @return DataResponse
+ * Get the app info for an app
+ *
+ * @param string $app ID of the app
+ * @return DataResponse<Http::STATUS_OK, array<string, ?mixed>, array{}>
* @throws OCSException
+ *
+ * 200: App info returned
*/
- public function getAppInfo($app) {
- $info = \OCP\App::getAppInfo($app);
- if(!is_null($info)) {
- return new DataResponse(OC_App::getAppInfo($app));
+ public function getAppInfo(string $app): DataResponse {
+ try {
+ $app = $this->verifyAppId($app);
+ } catch (\InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED);
+ }
+ $info = $this->appManager->getAppInfo($app);
+ if (!is_null($info)) {
+ return new DataResponse($info);
}
- throw new OCSException('The request app was not found', \OCP\API::RESPOND_NOT_FOUND);
+ throw new OCSException('The request app was not found', OCSController::RESPOND_NOT_FOUND);
}
/**
- * @PasswordConfirmationRequired
- * @param string $app
- * @return DataResponse
+ * Enable an app
+ *
+ * @param string $app ID of the app
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: App enabled successfully
*/
- public function enable($app) {
+ #[PasswordConfirmationRequired]
+ public function enable(string $app): DataResponse {
try {
+ $app = $this->verifyAppId($app);
+
+ if (!$this->installer->isDownloaded($app)) {
+ $this->installer->downloadApp($app);
+ }
+
+ if ($this->appConfig->getValueString($app, 'installed_version', '') === '') {
+ $this->installer->installApp($app);
+ }
+
$this->appManager->enableApp($app);
- } catch (AppPathNotFoundException $e) {
- throw new OCSException('The request app was not found', \OCP\API::RESPOND_NOT_FOUND);
+ } catch (\InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED);
+ } catch (AppPathNotFoundException|AppNotFoundException $e) {
+ throw new OCSException('The request app was not found', OCSController::RESPOND_NOT_FOUND);
}
return new DataResponse();
}
/**
- * @PasswordConfirmationRequired
- * @param string $app
- * @return DataResponse
+ * Disable an app
+ *
+ * @param string $app ID of the app
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSException
+ *
+ * 200: App disabled successfully
*/
- public function disable($app) {
- $this->appManager->disableApp($app);
+ #[PasswordConfirmationRequired]
+ public function disable(string $app): DataResponse {
+ try {
+ $app = $this->verifyAppId($app);
+ $this->appManager->disableApp($app);
+ } catch (\InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED);
+ }
return new DataResponse();
}
-
}
diff --git a/apps/provisioning_api/lib/Controller/GroupsController.php b/apps/provisioning_api/lib/Controller/GroupsController.php
index cb237d9791f..37af51419df 100644
--- a/apps/provisioning_api/lib/Controller/GroupsController.php
+++ b/apps/provisioning_api/lib/Controller/GroupsController.php
@@ -1,173 +1,318 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Provisioning_API\Controller;
+use OCA\Provisioning_API\ResponseDefinitions;
+use OCA\Settings\Settings\Admin\Sharing;
+use OCA\Settings\Settings\Admin\Users;
+use OCP\Accounts\IAccountManager;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
+use OCP\AppFramework\OCS\OCSForbiddenException;
+use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
+use OCP\Files\IRootFolder;
+use OCP\Group\ISubAdmin;
+use OCP\IConfig;
use OCP\IGroup;
use OCP\IGroupManager;
-use OCP\ILogger;
use OCP\IRequest;
-use OCP\IUserSession;
use OCP\IUser;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use OCP\L10N\IFactory;
+use Psr\Log\LoggerInterface;
+/**
+ * @psalm-import-type Provisioning_APIGroupDetails from ResponseDefinitions
+ * @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
+ */
+class GroupsController extends AUserDataOCSController {
-class GroupsController extends OCSController {
-
- /** @var IGroupManager */
- private $groupManager;
-
- /** @var IUserSession */
- private $userSession;
-
- /** @var ILogger */
- private $logger;
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ IUserManager $userManager,
+ IConfig $config,
+ IGroupManager $groupManager,
+ IUserSession $userSession,
+ IAccountManager $accountManager,
+ ISubAdmin $subAdminManager,
+ IFactory $l10nFactory,
+ IRootFolder $rootFolder,
+ private LoggerInterface $logger,
+ ) {
+ parent::__construct($appName,
+ $request,
+ $userManager,
+ $config,
+ $groupManager,
+ $userSession,
+ $accountManager,
+ $subAdminManager,
+ $l10nFactory,
+ $rootFolder,
+ );
+ }
/**
- * @param string $appName
- * @param IRequest $request
- * @param IGroupManager $groupManager
- * @param IUserSession $userSession
- * @param ILogger $logger
+ * Get a list of groups
+ *
+ * @param string $search Text to search for
+ * @param ?int $limit Limit the amount of groups returned
+ * @param int $offset Offset for searching for groups
+ * @return DataResponse<Http::STATUS_OK, array{groups: list<string>}, array{}>
+ *
+ * 200: Groups returned
*/
- public function __construct(
- $appName,
- IRequest $request,
- IGroupManager $groupManager,
- IUserSession $userSession,
- ILogger $logger) {
- parent::__construct($appName, $request);
-
- $this->groupManager = $groupManager;
- $this->userSession = $userSession;
- $this->logger = $logger;
+ #[NoAdminRequired]
+ public function getGroups(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
+ $groups = $this->groupManager->search($search, $limit, $offset);
+ $groups = array_values(array_map(function ($group) {
+ /** @var IGroup $group */
+ return $group->getGID();
+ }, $groups));
+
+ return new DataResponse(['groups' => $groups]);
}
/**
- * returns a list of groups
+ * Get a list of groups details
*
- * @NoAdminRequired
+ * @param string $search Text to search for
+ * @param ?int $limit Limit the amount of groups returned
+ * @param int $offset Offset for searching for groups
+ * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
*
- * @param string $search
- * @param int $limit
- * @param int $offset
- * @return DataResponse
+ * 200: Groups details returned
*/
- public function getGroups($search = '', $limit = null, $offset = null) {
- if ($limit !== null) {
- $limit = (int)$limit;
- }
- if ($offset !== null) {
- $offset = (int)$offset;
- }
-
+ #[NoAdminRequired]
+ #[AuthorizedAdminSetting(settings: Sharing::class)]
+ #[AuthorizedAdminSetting(settings: Users::class)]
+ public function getGroupsDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
$groups = $this->groupManager->search($search, $limit, $offset);
- $groups = array_map(function($group) {
+ $groups = array_values(array_map(function ($group) {
/** @var IGroup $group */
- return $group->getGID();
- }, $groups);
+ return [
+ 'id' => $group->getGID(),
+ 'displayname' => $group->getDisplayName(),
+ 'usercount' => $group->count(),
+ 'disabled' => $group->countDisabled(),
+ 'canAdd' => $group->canAddUser(),
+ 'canRemove' => $group->canRemoveUser(),
+ ];
+ }, $groups));
return new DataResponse(['groups' => $groups]);
}
/**
- * returns an array of users in the group specified
+ * Get a list of users in the specified group
*
- * @NoAdminRequired
+ * @param string $groupId ID of the group
+ * @return DataResponse<Http::STATUS_OK, array{users: list<string>}, array{}>
+ * @throws OCSException
+ *
+ * @deprecated 14 Use getGroupUsers
+ *
+ * 200: Group users returned
+ */
+ #[NoAdminRequired]
+ public function getGroup(string $groupId): DataResponse {
+ return $this->getGroupUsers($groupId);
+ }
+
+ /**
+ * Get a list of users in the specified group
*
- * @param string $groupId
- * @return DataResponse
+ * @param string $groupId ID of the group
+ * @return DataResponse<Http::STATUS_OK, array{users: list<string>}, array{}>
* @throws OCSException
+ * @throws OCSNotFoundException Group not found
+ * @throws OCSForbiddenException Missing permissions to get users in the group
+ *
+ * 200: User IDs returned
*/
- public function getGroup($groupId) {
+ #[NoAdminRequired]
+ public function getGroupUsers(string $groupId): DataResponse {
+ $groupId = urldecode($groupId);
+
$user = $this->userSession->getUser();
+ $isSubadminOfGroup = false;
// Check the group exists
- if(!$this->groupManager->groupExists($groupId)) {
- throw new OCSException('The requested group could not be found', \OCP\API::RESPOND_NOT_FOUND);
- }
-
- $isSubadminOfGroup = false;
$group = $this->groupManager->get($groupId);
if ($group !== null) {
- $isSubadminOfGroup =$this->groupManager->getSubAdmin()->isSubAdminofGroup($user, $group);
+ $isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($user, $group);
+ } else {
+ throw new OCSNotFoundException('The requested group could not be found');
}
// Check subadmin has access to this group
- if($this->groupManager->isAdmin($user->getUID())
- || $isSubadminOfGroup) {
+ $isAdmin = $this->groupManager->isAdmin($user->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($user->getUID());
+ if ($isAdmin || $isDelegatedAdmin || $isSubadminOfGroup) {
$users = $this->groupManager->get($groupId)->getUsers();
- $users = array_map(function($user) {
+ $users = array_map(function ($user) {
/** @var IUser $user */
return $user->getUID();
}, $users);
+ /** @var list<string> $users */
$users = array_values($users);
return new DataResponse(['users' => $users]);
}
- throw new OCSException('User does not have access to specified group', \OCP\API::RESPOND_UNAUTHORISED);
+ throw new OCSForbiddenException();
}
/**
- * creates a new group
+ * Get a list of users details in the specified group
*
- * @PasswordConfirmationRequired
+ * @param string $groupId ID of the group
+ * @param string $search Text to search for
+ * @param int|null $limit Limit the amount of groups returned
+ * @param int $offset Offset for searching for groups
*
- * @param string $groupid
- * @return DataResponse
+ * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
* @throws OCSException
+ *
+ * 200: Group users details returned
+ */
+ #[NoAdminRequired]
+ public function getGroupUsersDetails(string $groupId, string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
+ $groupId = urldecode($groupId);
+ $currentUser = $this->userSession->getUser();
+
+ // Check the group exists
+ $group = $this->groupManager->get($groupId);
+ if ($group !== null) {
+ $isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($currentUser, $group);
+ } else {
+ throw new OCSException('The requested group could not be found', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ // Check subadmin has access to this group
+ $isAdmin = $this->groupManager->isAdmin($currentUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentUser->getUID());
+ if ($isAdmin || $isDelegatedAdmin || $isSubadminOfGroup) {
+ $users = $group->searchUsers($search, $limit, $offset);
+
+ // Extract required number
+ $usersDetails = [];
+ foreach ($users as $user) {
+ try {
+ /** @var IUser $user */
+ $userId = (string)$user->getUID();
+ $userData = $this->getUserData($userId);
+ // Do not insert empty entry
+ if ($userData !== null) {
+ $usersDetails[$userId] = $userData;
+ } else {
+ // Logged user does not have permissions to see this user
+ // only showing its id
+ $usersDetails[$userId] = ['id' => $userId];
+ }
+ } catch (OCSNotFoundException $e) {
+ // continue if a users ceased to exist.
+ }
+ }
+ return new DataResponse(['users' => $usersDetails]);
+ }
+
+ throw new OCSException('The requested group could not be found', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ /**
+ * Create a new group
+ *
+ * @param string $groupid ID of the group
+ * @param string $displayname Display name of the group
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSException
+ *
+ * 200: Group created successfully
*/
- public function addGroup($groupid) {
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ #[PasswordConfirmationRequired]
+ public function addGroup(string $groupid, string $displayname = ''): DataResponse {
// Validate name
- if(empty($groupid)) {
+ if (empty($groupid)) {
$this->logger->error('Group name not supplied', ['app' => 'provisioning_api']);
throw new OCSException('Invalid group name', 101);
}
// Check if it exists
- if($this->groupManager->groupExists($groupid)){
- throw new OCSException('', 102);
+ if ($this->groupManager->groupExists($groupid)) {
+ throw new OCSException('group exists', 102);
+ }
+ $group = $this->groupManager->createGroup($groupid);
+ if ($group === null) {
+ throw new OCSException('Not supported by backend', 103);
+ }
+ if ($displayname !== '') {
+ $group->setDisplayName($displayname);
}
- $this->groupManager->createGroup($groupid);
return new DataResponse();
}
/**
- * @PasswordConfirmationRequired
+ * Update a group
+ *
+ * @param string $groupId ID of the group
+ * @param string $key Key to update, only 'displayname'
+ * @param string $value New value for the key
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSException
+ *
+ * 200: Group updated successfully
+ */
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ #[PasswordConfirmationRequired]
+ public function updateGroup(string $groupId, string $key, string $value): DataResponse {
+ $groupId = urldecode($groupId);
+
+ if ($key === 'displayname') {
+ $group = $this->groupManager->get($groupId);
+ if ($group === null) {
+ throw new OCSException('Group does not exist', OCSController::RESPOND_NOT_FOUND);
+ }
+ if ($group->setDisplayName($value)) {
+ return new DataResponse();
+ }
+
+ throw new OCSException('Not supported by backend', 101);
+ } else {
+ throw new OCSException('', OCSController::RESPOND_UNKNOWN_ERROR);
+ }
+ }
+
+ /**
+ * Delete a group
*
- * @param string $groupId
- * @return DataResponse
+ * @param string $groupId ID of the group
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: Group deleted successfully
*/
- public function deleteGroup($groupId) {
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ #[PasswordConfirmationRequired]
+ public function deleteGroup(string $groupId): DataResponse {
+ $groupId = urldecode($groupId);
+
// Check it exists
- if(!$this->groupManager->groupExists($groupId)){
+ if (!$this->groupManager->groupExists($groupId)) {
throw new OCSException('', 101);
- } else if($groupId === 'admin' || !$this->groupManager->get($groupId)->delete()){
+ } elseif ($groupId === 'admin' || !$this->groupManager->get($groupId)->delete()) {
// Cannot delete admin group
throw new OCSException('', 102);
}
@@ -176,20 +321,26 @@ class GroupsController extends OCSController {
}
/**
- * @param string $groupId
- * @return DataResponse
+ * Get the list of user IDs that are a subadmin of the group
+ *
+ * @param string $groupId ID of the group
+ * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
* @throws OCSException
+ *
+ * 200: Sub admins returned
*/
- public function getSubAdminsOfGroup($groupId) {
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ public function getSubAdminsOfGroup(string $groupId): DataResponse {
// Check group exists
$targetGroup = $this->groupManager->get($groupId);
- if($targetGroup === null) {
+ if ($targetGroup === null) {
throw new OCSException('Group does not exist', 101);
}
/** @var IUser[] $subadmins */
$subadmins = $this->groupManager->getSubAdmin()->getGroupsSubAdmins($targetGroup);
// New class returns IUser[] so convert back
+ /** @var list<string> $uids */
$uids = [];
foreach ($subadmins as $user) {
$uids[] = $user->getUID();
@@ -197,5 +348,4 @@ class GroupsController extends OCSController {
return new DataResponse($uids);
}
-
}
diff --git a/apps/provisioning_api/lib/Controller/PreferencesController.php b/apps/provisioning_api/lib/Controller/PreferencesController.php
new file mode 100644
index 00000000000..8ae64e65b81
--- /dev/null
+++ b/apps/provisioning_api/lib/Controller/PreferencesController.php
@@ -0,0 +1,201 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Provisioning_API\Controller;
+
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\OCSController;
+use OCP\Config\BeforePreferenceDeletedEvent;
+use OCP\Config\BeforePreferenceSetEvent;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\IConfig;
+use OCP\IRequest;
+use OCP\IUserSession;
+
+class PreferencesController extends OCSController {
+
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private IConfig $config,
+ private IUserSession $userSession,
+ private IEventDispatcher $eventDispatcher,
+ ) {
+ parent::__construct($appName, $request);
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Update multiple preference values of an app
+ *
+ * @param string $appId ID of the app
+ * @param array<string, string> $configs Key-value pairs of the preferences
+ *
+ * @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, list<empty>, array{}>
+ *
+ * 200: Preferences updated successfully
+ * 400: Preference invalid
+ */
+ #[NoAdminRequired]
+ public function setMultiplePreferences(string $appId, array $configs): DataResponse {
+ $userId = $this->userSession->getUser()->getUID();
+
+ foreach ($configs as $configKey => $configValue) {
+ $event = new BeforePreferenceSetEvent(
+ $userId,
+ $appId,
+ $configKey,
+ $configValue
+ );
+
+ $this->eventDispatcher->dispatchTyped($event);
+
+ if (!$event->isValid()) {
+ // No listener validated that the preference can be set (to this value)
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+ }
+
+ foreach ($configs as $configKey => $configValue) {
+ $this->config->setUserValue(
+ $userId,
+ $appId,
+ $configKey,
+ $configValue
+ );
+ }
+
+ return new DataResponse();
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Update a preference value of an app
+ *
+ * @param string $appId ID of the app
+ * @param string $configKey Key of the preference
+ * @param string $configValue New value
+ * @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, list<empty>, array{}>
+ *
+ * 200: Preference updated successfully
+ * 400: Preference invalid
+ */
+ #[NoAdminRequired]
+ public function setPreference(string $appId, string $configKey, string $configValue): DataResponse {
+ $userId = $this->userSession->getUser()->getUID();
+
+ $event = new BeforePreferenceSetEvent(
+ $userId,
+ $appId,
+ $configKey,
+ $configValue
+ );
+
+ $this->eventDispatcher->dispatchTyped($event);
+
+ if (!$event->isValid()) {
+ // No listener validated that the preference can be set (to this value)
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ $this->config->setUserValue(
+ $userId,
+ $appId,
+ $configKey,
+ $configValue
+ );
+
+ return new DataResponse();
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Delete multiple preferences for an app
+ *
+ * @param string $appId ID of the app
+ * @param list<string> $configKeys Keys to delete
+ *
+ * @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, list<empty>, array{}>
+ *
+ * 200: Preferences deleted successfully
+ * 400: Preference invalid
+ */
+ #[NoAdminRequired]
+ public function deleteMultiplePreference(string $appId, array $configKeys): DataResponse {
+ $userId = $this->userSession->getUser()->getUID();
+
+ foreach ($configKeys as $configKey) {
+ $event = new BeforePreferenceDeletedEvent(
+ $userId,
+ $appId,
+ $configKey
+ );
+
+ $this->eventDispatcher->dispatchTyped($event);
+
+ if (!$event->isValid()) {
+ // No listener validated that the preference can be deleted
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+ }
+
+ foreach ($configKeys as $configKey) {
+ $this->config->deleteUserValue(
+ $userId,
+ $appId,
+ $configKey
+ );
+ }
+
+ return new DataResponse();
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Delete a preference for an app
+ *
+ * @param string $appId ID of the app
+ * @param string $configKey Key to delete
+ * @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, list<empty>, array{}>
+ *
+ * 200: Preference deleted successfully
+ * 400: Preference invalid
+ */
+ #[NoAdminRequired]
+ public function deletePreference(string $appId, string $configKey): DataResponse {
+ $userId = $this->userSession->getUser()->getUID();
+
+ $event = new BeforePreferenceDeletedEvent(
+ $userId,
+ $appId,
+ $configKey
+ );
+
+ $this->eventDispatcher->dispatchTyped($event);
+
+ if (!$event->isValid()) {
+ // No listener validated that the preference can be deleted
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ $this->config->deleteUserValue(
+ $userId,
+ $appId,
+ $configKey
+ );
+
+ return new DataResponse();
+ }
+}
diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php
index ffae68d5a95..513a27c7df8 100644
--- a/apps/provisioning_api/lib/Controller/UsersController.php
+++ b/apps/provisioning_api/lib/Controller/UsersController.php
@@ -1,460 +1,1336 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author michag86 <micha_g@arcor.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Provisioning_API\Controller;
-use OC\Accounts\AccountManager;
-use OC\Settings\Mailer\NewUserMailHelper;
-use OC_Helper;
+use InvalidArgumentException;
+use OC\Authentication\Token\RemoteWipe;
+use OC\Group\Group;
+use OC\KnownUser\KnownUserService;
+use OC\User\Backend;
+use OCA\Provisioning_API\ResponseDefinitions;
+use OCA\Settings\Mailer\NewUserMailHelper;
+use OCA\Settings\Settings\Admin\Users;
+use OCP\Accounts\IAccountManager;
+use OCP\Accounts\IAccountProperty;
+use OCP\Accounts\PropertyDoesNotExistException;
use OCP\App\IAppManager;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
+use OCP\AppFramework\Http\Attribute\UserRateLimit;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCS\OCSForbiddenException;
+use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
-use OCP\Files\NotFoundException;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\IRootFolder;
+use OCP\Group\ISubAdmin;
+use OCP\HintException;
use OCP\IConfig;
use OCP\IGroup;
use OCP\IGroupManager;
-use OCP\ILogger;
+use OCP\IL10N;
+use OCP\IPhoneNumberUtil;
use OCP\IRequest;
+use OCP\IURLGenerator;
+use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory;
+use OCP\Security\Events\GenerateSecurePasswordEvent;
+use OCP\Security\ISecureRandom;
+use OCP\User\Backend\ISetDisplayNameBackend;
+use OCP\Util;
+use Psr\Log\LoggerInterface;
-class UsersController extends OCSController {
-
- /** @var IUserManager */
- private $userManager;
- /** @var IConfig */
- private $config;
- /** @var IAppManager */
- private $appManager;
- /** @var IGroupManager|\OC\Group\Manager */ // FIXME Requires a method that is not on the interface
- private $groupManager;
- /** @var IUserSession */
- private $userSession;
- /** @var AccountManager */
- private $accountManager;
- /** @var ILogger */
- private $logger;
- /** @var IFactory */
- private $l10nFactory;
- /** @var NewUserMailHelper */
- private $newUserMailHelper;
-
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IUserManager $userManager
- * @param IConfig $config
- * @param IAppManager $appManager
- * @param IGroupManager $groupManager
- * @param IUserSession $userSession
- * @param AccountManager $accountManager
- * @param ILogger $logger
- * @param IFactory $l10nFactory
- * @param NewUserMailHelper $newUserMailHelper
- */
- public function __construct($appName,
- IRequest $request,
- IUserManager $userManager,
- IConfig $config,
- IAppManager $appManager,
- IGroupManager $groupManager,
- IUserSession $userSession,
- AccountManager $accountManager,
- ILogger $logger,
- IFactory $l10nFactory,
- NewUserMailHelper $newUserMailHelper) {
- parent::__construct($appName, $request);
-
- $this->userManager = $userManager;
- $this->config = $config;
- $this->appManager = $appManager;
- $this->groupManager = $groupManager;
- $this->userSession = $userSession;
- $this->accountManager = $accountManager;
- $this->logger = $logger;
- $this->l10nFactory = $l10nFactory;
- $this->newUserMailHelper = $newUserMailHelper;
+/**
+ * @psalm-import-type Provisioning_APIGroupDetails from ResponseDefinitions
+ * @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
+ */
+class UsersController extends AUserDataOCSController {
+
+ private IL10N $l10n;
+
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ IUserManager $userManager,
+ IConfig $config,
+ IGroupManager $groupManager,
+ IUserSession $userSession,
+ IAccountManager $accountManager,
+ ISubAdmin $subAdminManager,
+ IFactory $l10nFactory,
+ IRootFolder $rootFolder,
+ private IURLGenerator $urlGenerator,
+ private LoggerInterface $logger,
+ private NewUserMailHelper $newUserMailHelper,
+ private ISecureRandom $secureRandom,
+ private RemoteWipe $remoteWipe,
+ private KnownUserService $knownUserService,
+ private IEventDispatcher $eventDispatcher,
+ private IPhoneNumberUtil $phoneNumberUtil,
+ private IAppManager $appManager,
+ ) {
+ parent::__construct(
+ $appName,
+ $request,
+ $userManager,
+ $config,
+ $groupManager,
+ $userSession,
+ $accountManager,
+ $subAdminManager,
+ $l10nFactory,
+ $rootFolder,
+ );
+
+ $this->l10n = $l10nFactory->get($appName);
}
/**
- * @NoAdminRequired
+ * Get a list of users
*
- * returns a list of users
+ * @param string $search Text to search for
+ * @param int|null $limit Limit the amount of groups returned
+ * @param int $offset Offset for searching for groups
+ * @return DataResponse<Http::STATUS_OK, array{users: list<string>}, array{}>
*
- * @param string $search
- * @param int $limit
- * @param int $offset
- * @return DataResponse
+ * 200: Users returned
*/
- public function getUsers($search = '', $limit = null, $offset = null) {
+ #[NoAdminRequired]
+ public function getUsers(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
$user = $this->userSession->getUser();
$users = [];
// Admin? Or SubAdmin?
$uid = $user->getUID();
$subAdminManager = $this->groupManager->getSubAdmin();
- if($this->groupManager->isAdmin($uid)){
+ $isAdmin = $this->groupManager->isAdmin($uid);
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
+ if ($isAdmin || $isDelegatedAdmin) {
$users = $this->userManager->search($search, $limit, $offset);
- } else if ($subAdminManager->isSubAdmin($user)) {
+ } elseif ($subAdminManager->isSubAdmin($user)) {
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
foreach ($subAdminOfGroups as $key => $group) {
$subAdminOfGroups[$key] = $group->getGID();
}
- if($offset === null) {
- $offset = 0;
+ $users = [];
+ foreach ($subAdminOfGroups as $group) {
+ $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
+ }
+ }
+
+ /** @var list<string> $users */
+ $users = array_keys($users);
+
+ return new DataResponse([
+ 'users' => $users
+ ]);
+ }
+
+ /**
+ * Get a list of users and their details
+ *
+ * @param string $search Text to search for
+ * @param int|null $limit Limit the amount of groups returned
+ * @param int $offset Offset for searching for groups
+ * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
+ *
+ * 200: Users details returned
+ */
+ #[NoAdminRequired]
+ public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
+ $currentUser = $this->userSession->getUser();
+ $users = [];
+
+ // Admin? Or SubAdmin?
+ $uid = $currentUser->getUID();
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $isAdmin = $this->groupManager->isAdmin($uid);
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
+ if ($isAdmin || $isDelegatedAdmin) {
+ $users = $this->userManager->search($search, $limit, $offset);
+ $users = array_keys($users);
+ } elseif ($subAdminManager->isSubAdmin($currentUser)) {
+ $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
+ foreach ($subAdminOfGroups as $key => $group) {
+ $subAdminOfGroups[$key] = $group->getGID();
}
$users = [];
foreach ($subAdminOfGroups as $group) {
- $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search));
+ $users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
}
+ $users = array_merge(...$users);
+ }
+ $usersDetails = [];
+ foreach ($users as $userId) {
+ $userId = (string)$userId;
+ try {
+ $userData = $this->getUserData($userId);
+ } catch (OCSNotFoundException $e) {
+ // We still want to return all other accounts, but this one was removed from the backends
+ // yet they are still in our database. Might be a LDAP remnant.
+ $userData = null;
+ $this->logger->warning('Found one enabled account that is removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
+ }
+ // Do not insert empty entry
+ if ($userData !== null) {
+ $usersDetails[$userId] = $userData;
+ } else {
+ // Logged user does not have permissions to see this user
+ // only showing its id
+ $usersDetails[$userId] = ['id' => $userId];
+ }
+ }
+
+ return new DataResponse([
+ 'users' => $usersDetails
+ ]);
+ }
+
+ /**
+ * Get the list of disabled users and their details
+ *
+ * @param string $search Text to search for
+ * @param ?int $limit Limit the amount of users returned
+ * @param int $offset Offset
+ * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
+ *
+ * 200: Disabled users details returned
+ */
+ #[NoAdminRequired]
+ public function getDisabledUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
+ $currentUser = $this->userSession->getUser();
+ if ($currentUser === null) {
+ return new DataResponse(['users' => []]);
+ }
+ if ($limit !== null && $limit < 0) {
+ throw new InvalidArgumentException("Invalid limit value: $limit");
+ }
+ if ($offset < 0) {
+ throw new InvalidArgumentException("Invalid offset value: $offset");
+ }
+
+ $users = [];
+
+ // Admin? Or SubAdmin?
+ $uid = $currentUser->getUID();
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $isAdmin = $this->groupManager->isAdmin($uid);
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
+ if ($isAdmin || $isDelegatedAdmin) {
+ $users = $this->userManager->getDisabledUsers($limit, $offset, $search);
+ $users = array_map(fn (IUser $user): string => $user->getUID(), $users);
+ } elseif ($subAdminManager->isSubAdmin($currentUser)) {
+ $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
+
+ $users = [];
+ /* We have to handle offset ourselve for correctness */
+ $tempLimit = ($limit === null ? null : $limit + $offset);
+ foreach ($subAdminOfGroups as $group) {
+ $users = array_unique(array_merge(
+ $users,
+ array_map(
+ fn (IUser $user): string => $user->getUID(),
+ array_filter(
+ $group->searchUsers($search),
+ fn (IUser $user): bool => !$user->isEnabled()
+ )
+ )
+ ));
+ if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
+ break;
+ }
+ }
$users = array_slice($users, $offset, $limit);
}
- $users = array_keys($users);
+ $usersDetails = [];
+ foreach ($users as $userId) {
+ try {
+ $userData = $this->getUserData($userId);
+ } catch (OCSNotFoundException $e) {
+ // We still want to return all other accounts, but this one was removed from the backends
+ // yet they are still in our database. Might be a LDAP remnant.
+ $userData = null;
+ $this->logger->warning('Found one disabled account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
+ }
+ // Do not insert empty entry
+ if ($userData !== null) {
+ $usersDetails[$userId] = $userData;
+ } else {
+ // Currently logged in user does not have permissions to see this user
+ // only showing its id
+ $usersDetails[$userId] = ['id' => $userId];
+ }
+ }
return new DataResponse([
- 'users' => $users
+ 'users' => $usersDetails
+ ]);
+ }
+
+ /**
+ * Gets the list of users sorted by lastLogin, from most recent to least recent
+ *
+ * @param string $search Text to search for
+ * @param ?int $limit Limit the amount of users returned
+ * @param int $offset Offset
+ * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
+ *
+ * 200: Users details returned based on last logged in information
+ */
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ public function getLastLoggedInUsers(string $search = '',
+ ?int $limit = null,
+ int $offset = 0,
+ ): DataResponse {
+ $currentUser = $this->userSession->getUser();
+ if ($currentUser === null) {
+ return new DataResponse(['users' => []]);
+ }
+ if ($limit !== null && $limit < 0) {
+ throw new InvalidArgumentException("Invalid limit value: $limit");
+ }
+ if ($offset < 0) {
+ throw new InvalidArgumentException("Invalid offset value: $offset");
+ }
+
+ $users = [];
+
+ // For Admin alone user sorting based on lastLogin. For sub admin and groups this is not supported
+ $users = $this->userManager->getLastLoggedInUsers($limit, $offset, $search);
+
+ $usersDetails = [];
+ foreach ($users as $userId) {
+ try {
+ $userData = $this->getUserData($userId);
+ } catch (OCSNotFoundException $e) {
+ // We still want to return all other accounts, but this one was removed from the backends
+ // yet they are still in our database. Might be a LDAP remnant.
+ $userData = null;
+ $this->logger->warning('Found one account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
+ }
+ // Do not insert empty entry
+ if ($userData !== null) {
+ $usersDetails[$userId] = $userData;
+ } else {
+ // Currently logged-in user does not have permissions to see this user
+ // only showing its id
+ $usersDetails[$userId] = ['id' => $userId];
+ }
+ }
+
+ return new DataResponse([
+ 'users' => $usersDetails
]);
}
+
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Search users by their phone numbers
+ *
+ * @param string $location Location of the phone number (for country code)
+ * @param array<string, list<string>> $search Phone numbers to search for
+ * @return DataResponse<Http::STATUS_OK, array<string, string>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, list<empty>, array{}>
+ *
+ * 200: Users returned
+ * 400: Invalid location
+ */
+ #[NoAdminRequired]
+ public function searchByPhoneNumbers(string $location, array $search): DataResponse {
+ if ($this->phoneNumberUtil->getCountryCodeForRegion($location) === null) {
+ // Not a valid region code
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ /** @var IUser $user */
+ $user = $this->userSession->getUser();
+ $knownTo = $user->getUID();
+ $defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
+
+ $normalizedNumberToKey = [];
+ foreach ($search as $key => $phoneNumbers) {
+ foreach ($phoneNumbers as $phone) {
+ $normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $location);
+ if ($normalizedNumber !== null) {
+ $normalizedNumberToKey[$normalizedNumber] = (string)$key;
+ }
+
+ if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && str_starts_with($phone, '0')) {
+ // If the number has a leading zero (no country code),
+ // we also check the default phone region of the instance,
+ // when it's different to the user's given region.
+ $normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $defaultPhoneRegion);
+ if ($normalizedNumber !== null) {
+ $normalizedNumberToKey[$normalizedNumber] = (string)$key;
+ }
+ }
+ }
+ }
+
+ $phoneNumbers = array_keys($normalizedNumberToKey);
+
+ if (empty($phoneNumbers)) {
+ return new DataResponse();
+ }
+
+ // Cleanup all previous entries and only allow new matches
+ $this->knownUserService->deleteKnownTo($knownTo);
+
+ $userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
+
+ if (empty($userMatches)) {
+ return new DataResponse();
+ }
+
+ $cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
+ if (strpos($cloudUrl, 'http://') === 0) {
+ $cloudUrl = substr($cloudUrl, strlen('http://'));
+ } elseif (strpos($cloudUrl, 'https://') === 0) {
+ $cloudUrl = substr($cloudUrl, strlen('https://'));
+ }
+
+ $matches = [];
+ foreach ($userMatches as $phone => $userId) {
+ // Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
+ $matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
+ $this->knownUserService->storeIsKnownToUser($knownTo, $userId);
+ }
+
+ return new DataResponse($matches);
+ }
+
+ /**
+ * @throws OCSException
+ */
+ private function createNewUserId(): string {
+ $attempts = 0;
+ do {
+ $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
+ if (!$this->userManager->userExists($uidCandidate)) {
+ return $uidCandidate;
+ }
+ $attempts++;
+ } while ($attempts < 10);
+ throw new OCSException($this->l10n->t('Could not create non-existing user ID'), 111);
+ }
+
/**
- * @PasswordConfirmationRequired
- * @NoAdminRequired
+ * Create a new user
*
- * @param string $userid
- * @param string $password
- * @param array $groups
- * @return DataResponse
+ * @param string $userid ID of the user
+ * @param string $password Password of the user
+ * @param string $displayName Display name of the user
+ * @param string $email Email of the user
+ * @param list<string> $groups Groups of the user
+ * @param list<string> $subadmin Groups where the user is subadmin
+ * @param string $quota Quota of the user
+ * @param string $language Language of the user
+ * @param ?string $manager Manager of the user
+ * @return DataResponse<Http::STATUS_OK, array{id: string}, array{}>
* @throws OCSException
+ * @throws OCSForbiddenException Missing permissions to make user subadmin
+ *
+ * 200: User added successfully
*/
- public function addUser($userid, $password, $groups = null) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function addUser(
+ string $userid,
+ string $password = '',
+ string $displayName = '',
+ string $email = '',
+ array $groups = [],
+ array $subadmin = [],
+ string $quota = '',
+ string $language = '',
+ ?string $manager = null,
+ ): DataResponse {
$user = $this->userSession->getUser();
$isAdmin = $this->groupManager->isAdmin($user->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($user->getUID());
$subAdminManager = $this->groupManager->getSubAdmin();
- if($this->userManager->userExists($userid)) {
+ if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
+ $userid = $this->createNewUserId();
+ }
+
+ if ($this->userManager->userExists($userid)) {
$this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
- throw new OCSException('User already exists', 102);
+ throw new OCSException($this->l10n->t('User already exists'), 102);
}
- if(is_array($groups)) {
+ if ($groups !== []) {
foreach ($groups as $group) {
- if(!$this->groupManager->groupExists($group)) {
- throw new OCSException('group '.$group.' does not exist', 104);
+ if (!$this->groupManager->groupExists($group)) {
+ throw new OCSException($this->l10n->t('Group %1$s does not exist', [$group]), 104);
}
- if(!$isAdmin && !$subAdminManager->isSubAdminofGroup($user, $this->groupManager->get($group))) {
- throw new OCSException('insufficient privileges for group '. $group, 105);
+ if (!$isAdmin && !($isDelegatedAdmin && $group !== 'admin') && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
+ throw new OCSException($this->l10n->t('Insufficient privileges for group %1$s', [$group]), 105);
}
}
} else {
- if(!$isAdmin) {
- throw new OCSException('no group specified (required for subadmins)', 106);
+ if (!$isAdmin && !$isDelegatedAdmin) {
+ throw new OCSException($this->l10n->t('No group specified (required for sub-admins)'), 106);
}
}
+ $subadminGroups = [];
+ if ($subadmin !== []) {
+ foreach ($subadmin as $groupid) {
+ $group = $this->groupManager->get($groupid);
+ // Check if group exists
+ if ($group === null) {
+ throw new OCSException($this->l10n->t('Sub-admin group does not exist'), 109);
+ }
+ // Check if trying to make subadmin of admin group
+ if ($group->getGID() === 'admin') {
+ throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
+ }
+ // Check if has permission to promote subadmins
+ if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin && !$isDelegatedAdmin) {
+ throw new OCSForbiddenException($this->l10n->t('No permissions to promote sub-admins'));
+ }
+ $subadminGroups[] = $group;
+ }
+ }
+
+ $generatePasswordResetToken = false;
+ if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
+ throw new OCSException($this->l10n->t('Invalid password value'), 101);
+ }
+ if ($password === '') {
+ if ($email === '') {
+ throw new OCSException($this->l10n->t('An email address is required, to send a password link to the user.'), 108);
+ }
+
+ $passwordEvent = new GenerateSecurePasswordEvent();
+ $this->eventDispatcher->dispatchTyped($passwordEvent);
+
+ $password = $passwordEvent->getPassword();
+ if ($password === null) {
+ // Fallback: ensure to pass password_policy in any case
+ $password = $this->secureRandom->generate(10)
+ . $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
+ . $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
+ . $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
+ . $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
+ }
+ $generatePasswordResetToken = true;
+ }
+
+ $email = mb_strtolower(trim($email));
+ if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
+ throw new OCSException($this->l10n->t('Required email address was not provided'), 110);
+ }
+
+ // Create the user
try {
$newUser = $this->userManager->createUser($userid, $password);
- $this->logger->info('Successful addUser call with userid: '.$userid, ['app' => 'ocs_api']);
+ if (!$newUser instanceof IUser) {
+ // If the user is not an instance of IUser, it means the user creation failed
+ $this->logger->error('Failed addUser attempt: User creation failed.', ['app' => 'ocs_api']);
+ throw new OCSException($this->l10n->t('User creation failed'), 111);
+ }
- if (is_array($groups)) {
- foreach ($groups as $group) {
- $this->groupManager->get($group)->addUser($newUser);
- $this->logger->info('Added userid '.$userid.' to group '.$group, ['app' => 'ocs_api']);
+ $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
+ foreach ($groups as $group) {
+ $this->groupManager->get($group)->addUser($newUser);
+ $this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
+ }
+ foreach ($subadminGroups as $group) {
+ $subAdminManager->createSubAdmin($newUser, $group);
+ }
+
+ if ($displayName !== '') {
+ try {
+ $this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
+ } catch (OCSException $e) {
+ if ($newUser instanceof IUser) {
+ $newUser->delete();
+ }
+ throw $e;
}
}
- return new DataResponse();
+
+ if ($quota !== '') {
+ $this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
+ }
+
+ if ($language !== '') {
+ $this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
+ }
+
+ /**
+ * null -> nothing sent
+ * '' -> unset manager
+ * else -> set manager
+ */
+ if ($manager !== null) {
+ $this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
+ }
+
+ // Send new user mail only if a mail is set
+ if ($email !== '') {
+ $newUser->setSystemEMailAddress($email);
+ if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
+ try {
+ $emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
+ $this->newUserMailHelper->sendMail($newUser, $emailTemplate);
+ } catch (\Exception $e) {
+ // Mail could be failing hard or just be plain not configured
+ // Logging error as it is the hardest of the two
+ $this->logger->error(
+ "Unable to send the invitation mail to $email",
+ [
+ 'app' => 'ocs_api',
+ 'exception' => $e,
+ ]
+ );
+ }
+ }
+ }
+
+ return new DataResponse(['id' => $userid]);
+ } catch (HintException $e) {
+ $this->logger->warning(
+ 'Failed addUser attempt with hint exception.',
+ [
+ 'app' => 'ocs_api',
+ 'exception' => $e,
+ ]
+ );
+ throw new OCSException($e->getHint(), 107);
+ } catch (OCSException $e) {
+ $this->logger->warning(
+ 'Failed addUser attempt with ocs exception.',
+ [
+ 'app' => 'ocs_api',
+ 'exception' => $e,
+ ]
+ );
+ throw $e;
+ } catch (InvalidArgumentException $e) {
+ $this->logger->error(
+ 'Failed addUser attempt with invalid argument exception.',
+ [
+ 'app' => 'ocs_api',
+ 'exception' => $e,
+ ]
+ );
+ throw new OCSException($e->getMessage(), 101);
} catch (\Exception $e) {
- $this->logger->error('Failed addUser attempt with exception: '.$e->getMessage(), ['app' => 'ocs_api']);
+ $this->logger->error(
+ 'Failed addUser attempt with exception.',
+ [
+ 'app' => 'ocs_api',
+ 'exception' => $e
+ ]
+ );
throw new OCSException('Bad request', 101);
}
}
/**
- * @NoAdminRequired
* @NoSubAdminRequired
*
- * gets user info
+ * Get the details of a user
*
- * @param string $userId
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
* @throws OCSException
+ *
+ * 200: User returned
*/
- public function getUser($userId) {
- $data = $this->getUserData($userId);
+ #[NoAdminRequired]
+ public function getUser(string $userId): DataResponse {
+ $includeScopes = false;
+ $currentUser = $this->userSession->getUser();
+ if ($currentUser && $currentUser->getUID() === $userId) {
+ $includeScopes = true;
+ }
+
+ $data = $this->getUserData($userId, $includeScopes);
+ // getUserData returns null if not enough permissions
+ if ($data === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
return new DataResponse($data);
}
/**
- * @NoAdminRequired
* @NoSubAdminRequired
*
- * gets user info from the currently logged in user
+ * Get the details of the current user
*
- * @return DataResponse
+ * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
* @throws OCSException
+ *
+ * 200: Current user returned
*/
- public function getCurrentUser() {
+ #[NoAdminRequired]
+ public function getCurrentUser(): DataResponse {
$user = $this->userSession->getUser();
if ($user) {
- $data = $this->getUserData($user->getUID());
- // rename "displayname" to "display-name" only for this call to keep
- // the API stable.
- $data['display-name'] = $data['displayname'];
- unset($data['displayname']);
+ /** @var Provisioning_APIUserDetails $data */
+ $data = $this->getUserData($user->getUID(), true);
return new DataResponse($data);
+ }
+ throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Get a list of fields that are editable for the current user
+ *
+ * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
+ * @throws OCSException
+ *
+ * 200: Editable fields returned
+ */
+ #[NoAdminRequired]
+ public function getEditableFields(): DataResponse {
+ $currentLoggedInUser = $this->userSession->getUser();
+ if (!$currentLoggedInUser instanceof IUser) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
+ }
+
+ /**
+ * Get a list of enabled apps for the current user
+ *
+ * @return DataResponse<Http::STATUS_OK, array{apps: list<string>}, array{}>
+ *
+ * 200: Enabled apps returned
+ */
+ #[NoAdminRequired]
+ public function getEnabledApps(): DataResponse {
+ $currentLoggedInUser = $this->userSession->getUser();
+ return new DataResponse(['apps' => $this->appManager->getEnabledAppsForUser($currentLoggedInUser)]);
}
/**
- * creates a array with all user data
+ * @NoSubAdminRequired
+ *
+ * Get a list of fields that are editable for a user
*
- * @param $userId
- * @return array
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
* @throws OCSException
+ *
+ * 200: Editable fields for user returned
*/
- protected function getUserData($userId) {
+ #[NoAdminRequired]
+ public function getEditableFieldsForUser(string $userId): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();
+ if (!$currentLoggedInUser instanceof IUser) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ $permittedFields = [];
- $data = [];
+ if ($userId !== $currentLoggedInUser->getUID()) {
+ $targetUser = $this->userManager->get($userId);
+ if (!$targetUser instanceof IUser) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
- // Check if the target user exists
- $targetUserObject = $this->userManager->get($userId);
- if($targetUserObject === null) {
- throw new OCSException('The requested user could not be found', \OCP\API::RESPOND_NOT_FOUND);
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if (
+ !($isAdmin || $isDelegatedAdmin)
+ && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
+ ) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+ } else {
+ $targetUser = $currentLoggedInUser;
}
- // Admin? Or SubAdmin?
- if($this->groupManager->isAdmin($currentLoggedInUser->getUID())
- || $this->groupManager->getSubAdmin()->isUserAccessible($currentLoggedInUser, $targetUserObject)) {
- $data['enabled'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true');
+ $allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
+ if ($allowDisplayNameChange === true && (
+ $targetUser->getBackend() instanceof ISetDisplayNameBackend
+ || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
+ )) {
+ $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
+ }
+
+ // Fallback to display name value to avoid changing behavior with the new option.
+ if ($this->config->getSystemValue('allow_user_to_change_email', $allowDisplayNameChange)) {
+ $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
+ }
+
+ $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
+ $permittedFields[] = IAccountManager::PROPERTY_PHONE;
+ $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
+ $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
+ $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
+ $permittedFields[] = IAccountManager::PROPERTY_BLUESKY;
+ $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
+ $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
+ $permittedFields[] = IAccountManager::PROPERTY_ROLE;
+ $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
+ $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
+ $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
+ $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
+
+ return new DataResponse($permittedFields);
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Update multiple values of the user's details
+ *
+ * @param string $userId ID of the user
+ * @param string $collectionName Collection to update
+ * @param string $key Key that will be updated
+ * @param string $value New value for the key
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSException
+ *
+ * 200: User values edited successfully
+ */
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ #[UserRateLimit(limit: 5, period: 60)]
+ public function editUserMultiValue(
+ string $userId,
+ string $collectionName,
+ string $key,
+ string $value,
+ ): DataResponse {
+ $currentLoggedInUser = $this->userSession->getUser();
+ if ($currentLoggedInUser === null) {
+ throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
+ }
+
+ $targetUser = $this->userManager->get($userId);
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ $isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
+ || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
+
+ $permittedFields = [];
+ if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
+ // Editing self (display, email)
+ $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
+ $permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
} else {
- // Check they are looking up themselves
- if($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ // Check if admin / subadmin
+ if ($isAdminOrSubadmin || $isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) {
+ // They have permissions over the user
+ $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
+ } else {
+ // No rights
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
}
- $userAccount = $this->accountManager->getUser($targetUserObject);
- $groups = $this->groupManager->getUserGroups($targetUserObject);
- $gids = [];
- foreach ($groups as $group) {
- $gids[] = $group->getDisplayName();
+ // Check if permitted to edit this field
+ if (!in_array($collectionName, $permittedFields)) {
+ throw new OCSException('', 103);
}
- // Find the data
- $data['id'] = $targetUserObject->getUID();
- $data['quota'] = $this->fillStorageInfo($targetUserObject->getUID());
- $data[AccountManager::PROPERTY_EMAIL] = $targetUserObject->getEMailAddress();
- $data[AccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
- $data[AccountManager::PROPERTY_PHONE] = $userAccount[AccountManager::PROPERTY_PHONE]['value'];
- $data[AccountManager::PROPERTY_ADDRESS] = $userAccount[AccountManager::PROPERTY_ADDRESS]['value'];
- $data[AccountManager::PROPERTY_WEBSITE] = $userAccount[AccountManager::PROPERTY_WEBSITE]['value'];
- $data[AccountManager::PROPERTY_TWITTER] = $userAccount[AccountManager::PROPERTY_TWITTER]['value'];
- $data['groups'] = $gids;
- $data['language'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'lang');
+ switch ($collectionName) {
+ case IAccountManager::COLLECTION_EMAIL:
+ $userAccount = $this->accountManager->getAccount($targetUser);
+ $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
+ $mailCollection->removePropertyByValue($key);
+ if ($value !== '') {
+ $value = mb_strtolower(trim($value));
+ $mailCollection->addPropertyWithDefaults($value);
+ $property = $mailCollection->getPropertyByValue($key);
+ if ($isAdminOrSubadmin && $property) {
+ // admin set mails are auto-verified
+ $property->setLocallyVerified(IAccountManager::VERIFIED);
+ }
+ }
+ $this->accountManager->updateAccount($userAccount);
+ if ($value === '' && $key === $targetUser->getPrimaryEMailAddress()) {
+ $targetUser->setPrimaryEMailAddress('');
+ }
+ break;
- return $data;
+ case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
+ $userAccount = $this->accountManager->getAccount($targetUser);
+ $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
+ $targetProperty = null;
+ foreach ($mailCollection->getProperties() as $property) {
+ if ($property->getValue() === $key) {
+ $targetProperty = $property;
+ break;
+ }
+ }
+ if ($targetProperty instanceof IAccountProperty) {
+ try {
+ $targetProperty->setScope($value);
+ $this->accountManager->updateAccount($userAccount);
+ } catch (InvalidArgumentException $e) {
+ throw new OCSException('', 102);
+ }
+ } else {
+ throw new OCSException('', 102);
+ }
+ break;
+
+ default:
+ throw new OCSException('', 103);
+ }
+ return new DataResponse();
}
/**
- * @NoAdminRequired
* @NoSubAdminRequired
- * @PasswordConfirmationRequired
*
- * edit users
+ * Update a value of the user's details
*
- * @param string $userId
- * @param string $key
- * @param string $value
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @param string $key Key that will be updated
+ * @param string $value New value for the key
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
- * @throws OCSForbiddenException
+ *
+ * 200: User value edited successfully
*/
- public function editUser($userId, $key, $value) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ #[UserRateLimit(limit: 50, period: 600)]
+ public function editUser(string $userId, string $key, string $value): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($userId);
- if($targetUser === null) {
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
$permittedFields = [];
- if($targetUser->getUID() === $currentLoggedInUser->getUID()) {
- // Editing self (display, email)
- if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
- $permittedFields[] = 'display';
- $permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
- $permittedFields[] = AccountManager::PROPERTY_EMAIL;
+ if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
+ $allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
+ if ($allowDisplayNameChange !== false && (
+ $targetUser->getBackend() instanceof ISetDisplayNameBackend
+ || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
+ )) {
+ $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
+ $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
- $permittedFields[] = 'password';
- if ($this->config->getSystemValue('force_language', false) === false ||
- $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
- $permittedFields[] = 'language';
+ // Fallback to display name value to avoid changing behavior with the new option.
+ if ($this->config->getSystemValue('allow_user_to_change_email', $allowDisplayNameChange)) {
+ $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
}
- if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
- $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
- $shareProvider = $federatedFileSharing->getFederatedShareProvider();
- if ($shareProvider->isLookupServerUploadEnabled()) {
- $permittedFields[] = AccountManager::PROPERTY_PHONE;
- $permittedFields[] = AccountManager::PROPERTY_ADDRESS;
- $permittedFields[] = AccountManager::PROPERTY_WEBSITE;
- $permittedFields[] = AccountManager::PROPERTY_TWITTER;
- }
+ $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
+
+ $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
+
+ $permittedFields[] = self::USER_FIELD_PASSWORD;
+ $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
+ if (
+ $this->config->getSystemValue('force_language', false) === false
+ || $this->groupManager->isAdmin($currentLoggedInUser->getUID())
+ || $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
+ ) {
+ $permittedFields[] = self::USER_FIELD_LANGUAGE;
+ }
+
+ if (
+ $this->config->getSystemValue('force_locale', false) === false
+ || $this->groupManager->isAdmin($currentLoggedInUser->getUID())
+ || $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
+ ) {
+ $permittedFields[] = self::USER_FIELD_LOCALE;
+ $permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
}
- // If admin they can edit their own quota
- if($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
- $permittedFields[] = 'quota';
+ $permittedFields[] = IAccountManager::PROPERTY_PHONE;
+ $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
+ $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
+ $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
+ $permittedFields[] = IAccountManager::PROPERTY_BLUESKY;
+ $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
+ $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
+ $permittedFields[] = IAccountManager::PROPERTY_ROLE;
+ $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
+ $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
+ $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
+ $permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE;
+ $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
+
+ $permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_BLUESKY . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
+ $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX;
+
+ // If admin they can edit their own quota and manager
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if ($isAdmin || $isDelegatedAdmin) {
+ $permittedFields[] = self::USER_FIELD_QUOTA;
+ $permittedFields[] = self::USER_FIELD_MANAGER;
}
} else {
// Check if admin / subadmin
$subAdminManager = $this->groupManager->getSubAdmin();
- if($subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
- || $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
+ if (
+ $this->groupManager->isAdmin($currentLoggedInUser->getUID())
+ || $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID()) && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')
+ || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
+ ) {
// They have permissions over the user
- $permittedFields[] = 'display';
- $permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
- $permittedFields[] = AccountManager::PROPERTY_EMAIL;
- $permittedFields[] = 'password';
- $permittedFields[] = 'language';
- $permittedFields[] = AccountManager::PROPERTY_PHONE;
- $permittedFields[] = AccountManager::PROPERTY_ADDRESS;
- $permittedFields[] = AccountManager::PROPERTY_WEBSITE;
- $permittedFields[] = AccountManager::PROPERTY_TWITTER;
- $permittedFields[] = 'quota';
+ if (
+ $targetUser->getBackend() instanceof ISetDisplayNameBackend
+ || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
+ ) {
+ $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
+ $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
+ }
+ $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
+ $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
+ $permittedFields[] = self::USER_FIELD_PASSWORD;
+ $permittedFields[] = self::USER_FIELD_LANGUAGE;
+ $permittedFields[] = self::USER_FIELD_LOCALE;
+ $permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
+ $permittedFields[] = IAccountManager::PROPERTY_PHONE;
+ $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
+ $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
+ $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
+ $permittedFields[] = IAccountManager::PROPERTY_BLUESKY;
+ $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
+ $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
+ $permittedFields[] = IAccountManager::PROPERTY_ROLE;
+ $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
+ $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
+ $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
+ $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
+ $permittedFields[] = self::USER_FIELD_QUOTA;
+ $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
+ $permittedFields[] = self::USER_FIELD_MANAGER;
} else {
// No rights
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
}
// Check if permitted to edit this field
- if(!in_array($key, $permittedFields)) {
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ if (!in_array($key, $permittedFields)) {
+ throw new OCSException('', 113);
}
// Process the edit
- switch($key) {
- case 'display':
- case AccountManager::PROPERTY_DISPLAYNAME:
- $targetUser->setDisplayName($value);
+ switch ($key) {
+ case self::USER_FIELD_DISPLAYNAME:
+ case IAccountManager::PROPERTY_DISPLAYNAME:
+ try {
+ $targetUser->setDisplayName($value);
+ } catch (InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), 101);
+ }
break;
- case 'quota':
+ case self::USER_FIELD_QUOTA:
$quota = $value;
- if($quota !== 'none' && $quota !== 'default') {
+ if ($quota !== 'none' && $quota !== 'default') {
if (is_numeric($quota)) {
- $quota = (float) $quota;
+ $quota = (float)$quota;
} else {
- $quota = \OCP\Util::computerFileSize($quota);
+ $quota = Util::computerFileSize($quota);
}
if ($quota === false) {
- throw new OCSException('Invalid quota value '.$value, 103);
+ throw new OCSException($this->l10n->t('Invalid quota value: %1$s', [$value]), 101);
}
- if($quota === 0) {
- $quota = 'default';
- }else if($quota === -1) {
+ if ($quota === -1) {
$quota = 'none';
} else {
- $quota = \OCP\Util::humanFileSize($quota);
+ $maxQuota = (int)$this->config->getAppValue('files', 'max_quota', '-1');
+ if ($maxQuota !== -1 && $quota > $maxQuota) {
+ throw new OCSException($this->l10n->t('Invalid quota value. %1$s is exceeding the maximum quota', [$value]), 101);
+ }
+ $quota = Util::humanFileSize($quota);
+ }
+ }
+ // no else block because quota can be set to 'none' in previous if
+ if ($quota === 'none') {
+ $allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
+ if (!$allowUnlimitedQuota) {
+ throw new OCSException($this->l10n->t('Unlimited quota is forbidden on this instance'), 101);
}
}
$targetUser->setQuota($quota);
break;
- case 'password':
- $targetUser->setPassword($value);
+ case self::USER_FIELD_MANAGER:
+ $targetUser->setManagerUids([$value]);
+ break;
+ case self::USER_FIELD_PASSWORD:
+ try {
+ if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
+ throw new OCSException($this->l10n->t('Invalid password value'), 101);
+ }
+ if (!$targetUser->canChangePassword()) {
+ throw new OCSException($this->l10n->t('Setting the password is not supported by the users backend'), 112);
+ }
+ $targetUser->setPassword($value);
+ } catch (HintException $e) { // password policy error
+ throw new OCSException($e->getHint(), 107);
+ }
break;
- case 'language':
+ case self::USER_FIELD_LANGUAGE:
$languagesCodes = $this->l10nFactory->findAvailableLanguages();
if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
- throw new OCSException('Invalid language', 102);
+ throw new OCSException($this->l10n->t('Invalid language'), 101);
}
$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
break;
- case AccountManager::PROPERTY_EMAIL:
- if(filter_var($value, FILTER_VALIDATE_EMAIL)) {
- $targetUser->setEMailAddress($value);
+ case self::USER_FIELD_LOCALE:
+ if (!$this->l10nFactory->localeExists($value)) {
+ throw new OCSException($this->l10n->t('Invalid locale'), 101);
+ }
+ $this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
+ break;
+ case self::USER_FIELD_FIRST_DAY_OF_WEEK:
+ $intValue = (int)$value;
+ if ($intValue < -1 || $intValue > 6) {
+ throw new OCSException($this->l10n->t('Invalid first day of week'), 101);
+ }
+ if ($intValue === -1) {
+ $this->config->deleteUserValue($targetUser->getUID(), 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK);
} else {
- throw new OCSException('', 102);
+ $this->config->setUserValue($targetUser->getUID(), 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK, $value);
}
break;
- case AccountManager::PROPERTY_PHONE:
- case AccountManager::PROPERTY_ADDRESS:
- case AccountManager::PROPERTY_WEBSITE:
- case AccountManager::PROPERTY_TWITTER:
- $userAccount = $this->accountManager->getUser($targetUser);
- if ($userAccount[$key]['value'] !== $value) {
- $userAccount[$key]['value'] = $value;
- $this->accountManager->updateUser($targetUser, $userAccount);
+ case self::USER_FIELD_NOTIFICATION_EMAIL:
+ $success = false;
+ if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
+ try {
+ $targetUser->setPrimaryEMailAddress($value);
+ $success = true;
+ } catch (InvalidArgumentException $e) {
+ $this->logger->info(
+ 'Cannot set primary email, because provided address is not verified',
+ [
+ 'app' => 'provisioning_api',
+ 'exception' => $e,
+ ]
+ );
+ }
+ }
+ if (!$success) {
+ throw new OCSException('', 101);
+ }
+ break;
+ case IAccountManager::PROPERTY_EMAIL:
+ $value = mb_strtolower(trim($value));
+ if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
+ $targetUser->setSystemEMailAddress($value);
+ } else {
+ throw new OCSException('', 101);
+ }
+ break;
+ case IAccountManager::COLLECTION_EMAIL:
+ $value = mb_strtolower(trim($value));
+ if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
+ $userAccount = $this->accountManager->getAccount($targetUser);
+ $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
+
+ if ($mailCollection->getPropertyByValue($value)) {
+ throw new OCSException('', 101);
+ }
+
+ $mailCollection->addPropertyWithDefaults($value);
+ $this->accountManager->updateAccount($userAccount);
+ } else {
+ throw new OCSException('', 101);
+ }
+ break;
+ case IAccountManager::PROPERTY_PHONE:
+ case IAccountManager::PROPERTY_ADDRESS:
+ case IAccountManager::PROPERTY_WEBSITE:
+ case IAccountManager::PROPERTY_TWITTER:
+ case IAccountManager::PROPERTY_BLUESKY:
+ case IAccountManager::PROPERTY_FEDIVERSE:
+ case IAccountManager::PROPERTY_ORGANISATION:
+ case IAccountManager::PROPERTY_ROLE:
+ case IAccountManager::PROPERTY_HEADLINE:
+ case IAccountManager::PROPERTY_BIOGRAPHY:
+ case IAccountManager::PROPERTY_BIRTHDATE:
+ case IAccountManager::PROPERTY_PRONOUNS:
+ $userAccount = $this->accountManager->getAccount($targetUser);
+ try {
+ $userProperty = $userAccount->getProperty($key);
+ if ($userProperty->getValue() !== $value) {
+ try {
+ $userProperty->setValue($value);
+ if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
+ $this->knownUserService->deleteByContactUserId($targetUser->getUID());
+ }
+ } catch (InvalidArgumentException $e) {
+ throw new OCSException('Invalid ' . $e->getMessage(), 101);
+ }
+ }
+ } catch (PropertyDoesNotExistException $e) {
+ $userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
+ }
+ try {
+ $this->accountManager->updateAccount($userAccount);
+ } catch (InvalidArgumentException $e) {
+ throw new OCSException('Invalid ' . $e->getMessage(), 101);
+ }
+ break;
+ case IAccountManager::PROPERTY_PROFILE_ENABLED:
+ $userAccount = $this->accountManager->getAccount($targetUser);
+ try {
+ $userProperty = $userAccount->getProperty($key);
+ if ($userProperty->getValue() !== $value) {
+ $userProperty->setValue($value);
+ }
+ } catch (PropertyDoesNotExistException $e) {
+ $userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
+ }
+ $this->accountManager->updateAccount($userAccount);
+ break;
+ case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_BLUESKY . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
+ case IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX:
+ $propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
+ $userAccount = $this->accountManager->getAccount($targetUser);
+ $userProperty = $userAccount->getProperty($propertyName);
+ if ($userProperty->getScope() !== $value) {
+ try {
+ $userProperty->setScope($value);
+ $this->accountManager->updateAccount($userAccount);
+ } catch (InvalidArgumentException $e) {
+ throw new OCSException('Invalid ' . $e->getMessage(), 101);
+ }
}
break;
default:
- throw new OCSException('', 103);
+ throw new OCSException('', 113);
}
return new DataResponse();
}
/**
- * @PasswordConfirmationRequired
- * @NoAdminRequired
+ * Wipe all devices of a user
*
- * @param string $userId
- * @return DataResponse
+ * @param string $userId ID of the user
+ *
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ *
+ * @throws OCSException
+ *
+ * 200: Wiped all user devices successfully
+ */
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function wipeUserDevices(string $userId): DataResponse {
+ /** @var IUser $currentLoggedInUser */
+ $currentLoggedInUser = $this->userSession->getUser();
+
+ $targetUser = $this->userManager->get($userId);
+
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
+ throw new OCSException('', 101);
+ }
+
+ // If not permitted
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ $this->remoteWipe->markAllTokensForWipe($targetUser);
+
+ return new DataResponse();
+ }
+
+ /**
+ * Delete a user
+ *
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
- * @throws OCSForbiddenException
+ *
+ * 200: User deleted successfully
*/
- public function deleteUser($userId) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function deleteUser(string $userId): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($userId);
- if($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
throw new OCSException('', 101);
}
// If not permitted
$subAdminManager = $this->groupManager->getSubAdmin();
- if(!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
// Go ahead with the delete
- if($targetUser->delete()) {
+ if ($targetUser->delete()) {
return new DataResponse();
} else {
throw new OCSException('', 101);
@@ -462,50 +1338,55 @@ class UsersController extends OCSController {
}
/**
- * @PasswordConfirmationRequired
- * @NoAdminRequired
+ * Disable a user
*
- * @param string $userId
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
- * @throws OCSForbiddenException
+ *
+ * 200: User disabled successfully
*/
- public function disableUser($userId) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function disableUser(string $userId): DataResponse {
return $this->setEnabled($userId, false);
}
/**
- * @PasswordConfirmationRequired
- * @NoAdminRequired
+ * Enable a user
*
- * @param string $userId
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
- * @throws OCSForbiddenException
+ *
+ * 200: User enabled successfully
*/
- public function enableUser($userId) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function enableUser(string $userId): DataResponse {
return $this->setEnabled($userId, true);
}
/**
* @param string $userId
* @param bool $value
- * @return DataResponse
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
- * @throws OCSForbiddenException
*/
- private function setEnabled($userId, $value) {
+ private function setEnabled(string $userId, bool $value): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($userId);
- if($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
+ if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
throw new OCSException('', 101);
}
// If not permitted
$subAdminManager = $this->groupManager->getSubAdmin();
- if(!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
// enable/disable the user now
@@ -514,22 +1395,28 @@ class UsersController extends OCSController {
}
/**
- * @NoAdminRequired
* @NoSubAdminRequired
*
- * @param string $userId
- * @return DataResponse
+ * Get a list of groups the user belongs to
+ *
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, array{groups: list<string>}, array{}>
* @throws OCSException
+ *
+ * 200: Users groups returned
*/
- public function getUsersGroups($userId) {
+ #[NoAdminRequired]
+ public function getUsersGroups(string $userId): DataResponse {
$loggedInUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($userId);
- if($targetUser === null) {
- throw new OCSException('', \OCP\API::RESPOND_NOT_FOUND);
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
- if($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
+ $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
+ if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
// Self lookup or admin lookup
return new DataResponse([
'groups' => $this->groupManager->getUserGroupIds($targetUser)
@@ -538,53 +1425,173 @@ class UsersController extends OCSController {
$subAdminManager = $this->groupManager->getSubAdmin();
// Looking up someone else
- if($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
+ if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
// Return the group that the method caller is subadmin of for the user in question
- /** @var IGroup[] $getSubAdminsGroups */
- $getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
- foreach ($getSubAdminsGroups as $key => $group) {
- $getSubAdminsGroups[$key] = $group->getGID();
- }
- $groups = array_intersect(
- $getSubAdminsGroups,
+ $groups = array_values(array_intersect(
+ array_map(static fn (IGroup $group) => $group->getGID(), $subAdminManager->getSubAdminsGroups($loggedInUser)),
$this->groupManager->getUserGroupIds($targetUser)
- );
+ ));
return new DataResponse(['groups' => $groups]);
} else {
// Not permitted
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
}
+ }
+
+ /**
+ * @NoSubAdminRequired
+ *
+ * Get a list of groups with details
+ *
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
+ * @throws OCSException
+ *
+ * 200: Users groups returned
+ */
+ #[NoAdminRequired]
+ public function getUsersGroupsDetails(string $userId): DataResponse {
+ $loggedInUser = $this->userSession->getUser();
+
+ $targetUser = $this->userManager->get($userId);
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+ $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
+ if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
+ // Self lookup or admin lookup
+ $groups = array_map(
+ function (Group $group) {
+ return [
+ 'id' => $group->getGID(),
+ 'displayname' => $group->getDisplayName(),
+ 'usercount' => $group->count(),
+ 'disabled' => $group->countDisabled(),
+ 'canAdd' => $group->canAddUser(),
+ 'canRemove' => $group->canRemoveUser(),
+ ];
+ },
+ array_values($this->groupManager->getUserGroups($targetUser)),
+ );
+ return new DataResponse([
+ 'groups' => $groups,
+ ]);
+ } else {
+ $subAdminManager = $this->groupManager->getSubAdmin();
+
+ // Looking up someone else
+ if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
+ // Return the group that the method caller is subadmin of for the user in question
+ $gids = array_values(array_intersect(
+ array_map(
+ static fn (IGroup $group) => $group->getGID(),
+ $subAdminManager->getSubAdminsGroups($loggedInUser),
+ ),
+ $this->groupManager->getUserGroupIds($targetUser)
+ ));
+ $groups = array_map(
+ function (string $gid) {
+ $group = $this->groupManager->get($gid);
+ return [
+ 'id' => $group->getGID(),
+ 'displayname' => $group->getDisplayName(),
+ 'usercount' => $group->count(),
+ 'disabled' => $group->countDisabled(),
+ 'canAdd' => $group->canAddUser(),
+ 'canRemove' => $group->canRemoveUser(),
+ ];
+ },
+ $gids,
+ );
+ return new DataResponse([
+ 'groups' => $groups,
+ ]);
+ } else {
+ // Not permitted
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+ }
}
/**
- * @PasswordConfirmationRequired
- * @NoAdminRequired
+ * @NoSubAdminRequired
*
- * @param string $userId
- * @param string $groupid
- * @return DataResponse
+ * Get a list of the groups the user is a subadmin of, with details
+ *
+ * @param string $userId ID of the user
+ * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
* @throws OCSException
+ *
+ * 200: Users subadmin groups returned
*/
- public function addToGroup($userId, $groupid = '') {
- if($groupid === '') {
+ #[NoAdminRequired]
+ public function getUserSubAdminGroupsDetails(string $userId): DataResponse {
+ $loggedInUser = $this->userSession->getUser();
+
+ $targetUser = $this->userManager->get($userId);
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
+ if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
+ $subAdminManager = $this->groupManager->getSubAdmin();
+ $groups = array_map(
+ function (IGroup $group) {
+ return [
+ 'id' => $group->getGID(),
+ 'displayname' => $group->getDisplayName(),
+ 'usercount' => $group->count(),
+ 'disabled' => $group->countDisabled(),
+ 'canAdd' => $group->canAddUser(),
+ 'canRemove' => $group->canRemoveUser(),
+ ];
+ },
+ array_values($subAdminManager->getSubAdminsGroups($targetUser)),
+ );
+ return new DataResponse([
+ 'groups' => $groups,
+ ]);
+ }
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
+ }
+
+ /**
+ * Add a user to a group
+ *
+ * @param string $userId ID of the user
+ * @param string $groupid ID of the group
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSException
+ *
+ * 200: User added to group successfully
+ */
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function addToGroup(string $userId, string $groupid = ''): DataResponse {
+ if ($groupid === '') {
throw new OCSException('', 101);
}
$group = $this->groupManager->get($groupid);
$targetUser = $this->userManager->get($userId);
- if($group === null) {
+ if ($group === null) {
throw new OCSException('', 102);
}
- if($targetUser === null) {
+ if ($targetUser === null) {
throw new OCSException('', 103);
}
// If they're not an admin, check they are a subadmin of the group in question
$loggedInUser = $this->userSession->getUser();
$subAdminManager = $this->groupManager->getSubAdmin();
- if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
+ $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
+ if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
throw new OCSException('', 104);
}
@@ -594,49 +1601,53 @@ class UsersController extends OCSController {
}
/**
- * @PasswordConfirmationRequired
- * @NoAdminRequired
+ * Remove a user from a group
*
- * @param string $userId
- * @param string $groupid
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @param string $groupid ID of the group
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: User removed from group successfully
*/
- public function removeFromGroup($userId, $groupid) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function removeFromGroup(string $userId, string $groupid): DataResponse {
$loggedInUser = $this->userSession->getUser();
- if($groupid === null || trim($groupid) === '') {
+ if ($groupid === null || trim($groupid) === '') {
throw new OCSException('', 101);
}
$group = $this->groupManager->get($groupid);
- if($group === null) {
+ if ($group === null) {
throw new OCSException('', 102);
}
$targetUser = $this->userManager->get($userId);
- if($targetUser === null) {
+ if ($targetUser === null) {
throw new OCSException('', 103);
}
// If they're not an admin, check they are a subadmin of the group in question
$subAdminManager = $this->groupManager->getSubAdmin();
- if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
+ $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
+ if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
throw new OCSException('', 104);
}
// Check they aren't removing themselves from 'admin' or their 'subadmin; group
if ($targetUser->getUID() === $loggedInUser->getUID()) {
- if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
+ if ($isAdmin || $isDelegatedAdmin) {
if ($group->getGID() === 'admin') {
- throw new OCSException('Cannot remove yourself from the admin group', 105);
+ throw new OCSException($this->l10n->t('Cannot remove yourself from the admin group'), 105);
}
} else {
// Not an admin, so the user must be a subadmin of this group, but that is not allowed.
- throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
+ throw new OCSException($this->l10n->t('Cannot remove yourself from this group as you are a sub-admin'), 105);
}
-
- } else if (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
+ } elseif (!($isAdmin || $isDelegatedAdmin)) {
/** @var IGroup[] $subAdminGroups */
$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
@@ -647,7 +1658,7 @@ class UsersController extends OCSController {
if (count($userSubAdminGroups) <= 1) {
// Subadmin must not be able to remove a user from all their subadmin groups.
- throw new OCSException('Cannot remove user from this group as this is the only remaining group you are a SubAdmin of', 105);
+ throw new OCSException($this->l10n->t('Not viable to remove user from the last group you are sub-admin of'), 105);
}
}
@@ -657,177 +1668,148 @@ class UsersController extends OCSController {
}
/**
- * Creates a subadmin
- *
- * @PasswordConfirmationRequired
+ * Make a user a subadmin of a group
*
- * @param string $userId
- * @param string $groupid
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @param string $groupid ID of the group
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: User added as group subadmin successfully
*/
- public function addSubAdmin($userId, $groupid) {
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ #[PasswordConfirmationRequired]
+ public function addSubAdmin(string $userId, string $groupid): DataResponse {
$group = $this->groupManager->get($groupid);
$user = $this->userManager->get($userId);
// Check if the user exists
- if($user === null) {
- throw new OCSException('User does not exist', 101);
+ if ($user === null) {
+ throw new OCSException($this->l10n->t('User does not exist'), 101);
}
// Check if group exists
- if($group === null) {
- throw new OCSException('Group does not exist', 102);
+ if ($group === null) {
+ throw new OCSException($this->l10n->t('Group does not exist'), 102);
}
// Check if trying to make subadmin of admin group
- if($group->getGID() === 'admin') {
- throw new OCSException('Cannot create subadmins for admin group', 103);
+ if ($group->getGID() === 'admin') {
+ throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
}
$subAdminManager = $this->groupManager->getSubAdmin();
// We cannot be subadmin twice
- if ($subAdminManager->isSubAdminofGroup($user, $group)) {
+ if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
return new DataResponse();
}
// Go
- if($subAdminManager->createSubAdmin($user, $group)) {
- return new DataResponse();
- } else {
- throw new OCSException('Unknown error occurred', 103);
- }
+ $subAdminManager->createSubAdmin($user, $group);
+ return new DataResponse();
}
/**
- * Removes a subadmin from a group
- *
- * @PasswordConfirmationRequired
+ * Remove a user from the subadmins of a group
*
- * @param string $userId
- * @param string $groupid
- * @return DataResponse
+ * @param string $userId ID of the user
+ * @param string $groupid ID of the group
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: User removed as group subadmin successfully
*/
- public function removeSubAdmin($userId, $groupid) {
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ #[PasswordConfirmationRequired]
+ public function removeSubAdmin(string $userId, string $groupid): DataResponse {
$group = $this->groupManager->get($groupid);
$user = $this->userManager->get($userId);
$subAdminManager = $this->groupManager->getSubAdmin();
// Check if the user exists
- if($user === null) {
- throw new OCSException('User does not exist', 101);
+ if ($user === null) {
+ throw new OCSException($this->l10n->t('User does not exist'), 101);
}
// Check if the group exists
- if($group === null) {
- throw new OCSException('Group does not exist', 101);
+ if ($group === null) {
+ throw new OCSException($this->l10n->t('Group does not exist'), 101);
}
// Check if they are a subadmin of this said group
- if(!$subAdminManager->isSubAdminOfGroup($user, $group)) {
- throw new OCSException('User is not a subadmin of this group', 102);
+ if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
+ throw new OCSException($this->l10n->t('User is not a sub-admin of this group'), 102);
}
// Go
- if($subAdminManager->deleteSubAdmin($user, $group)) {
- return new DataResponse();
- } else {
- throw new OCSException('Unknown error occurred', 103);
- }
+ $subAdminManager->deleteSubAdmin($user, $group);
+ return new DataResponse();
}
/**
* Get the groups a user is a subadmin of
*
- * @param string $userId
- * @return DataResponse
+ * @param string $userId ID if the user
+ * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
* @throws OCSException
+ *
+ * 200: User subadmin groups returned
*/
- public function getUserSubAdminGroups($userId) {
- $user = $this->userManager->get($userId);
- // Check if the user exists
- if($user === null) {
- throw new OCSException('User does not exist', 101);
- }
-
- // Get the subadmin groups
- $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
- foreach ($groups as $key => $group) {
- $groups[$key] = $group->getGID();
- }
-
- if(!$groups) {
- throw new OCSException('Unknown error occurred', 102);
- } else {
- return new DataResponse($groups);
- }
- }
-
- /**
- * @param string $userId
- * @return array
- * @throws \OCP\Files\NotFoundException
- */
- protected function fillStorageInfo($userId) {
- try {
- \OC_Util::tearDownFS();
- \OC_Util::setupFS($userId);
- $storage = OC_Helper::getStorageInfo('/');
- $data = [
- 'free' => $storage['free'],
- 'used' => $storage['used'],
- 'total' => $storage['total'],
- 'relative' => $storage['relative'],
- 'quota' => $storage['quota'],
- ];
- } catch (NotFoundException $ex) {
- $data = [];
- }
- return $data;
+ #[AuthorizedAdminSetting(settings:Users::class)]
+ public function getUserSubAdminGroups(string $userId): DataResponse {
+ $groups = $this->getUserSubAdminGroupsData($userId);
+ return new DataResponse($groups);
}
/**
- * @NoAdminRequired
- * @PasswordConfirmationRequired
+ * Resend the welcome message
*
- * resend welcome message
- *
- * @param string $userId
- * @return DataResponse
+ * @param string $userId ID if the user
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
+ *
+ * 200: Resent welcome message successfully
*/
- public function resendWelcomeMessage($userId) {
+ #[PasswordConfirmationRequired]
+ #[NoAdminRequired]
+ public function resendWelcomeMessage(string $userId): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($userId);
- if($targetUser === null) {
- throw new OCSException('', \OCP\API::RESPOND_NOT_FOUND);
+ if ($targetUser === null) {
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
// Check if admin / subadmin
$subAdminManager = $this->groupManager->getSubAdmin();
- if(!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
- && !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
+ $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
+ $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
+ if (
+ !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
+ && !($isAdmin || $isDelegatedAdmin)
+ ) {
// No rights
- throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
+ throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
$email = $targetUser->getEMailAddress();
if ($email === '' || $email === null) {
- throw new OCSException('Email address not available', 101);
+ throw new OCSException($this->l10n->t('Email address not available'), 101);
}
- $username = $targetUser->getUID();
- $lang = $this->config->getUserValue($username, 'core', 'lang', 'en');
- if (!$this->l10nFactory->languageExists('settings', $lang)) {
- $lang = 'en';
- }
-
- $l10n = $this->l10nFactory->get('settings', $lang);
try {
- $this->newUserMailHelper->setL10N($l10n);
- $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
+ if ($this->config->getUserValue($targetUser->getUID(), 'core', 'lostpassword')) {
+ $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, true);
+ } else {
+ $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
+ }
+
$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
- } catch(\Exception $e) {
- $this->logger->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
- throw new OCSException('Sending email failed', 102);
+ } catch (\Exception $e) {
+ $this->logger->error(
+ "Can't send new user mail to $email",
+ [
+ 'app' => 'settings',
+ 'exception' => $e,
+ ]
+ );
+ throw new OCSException($this->l10n->t('Sending email failed'), 102);
}
return new DataResponse();
diff --git a/apps/provisioning_api/lib/Controller/VerificationController.php b/apps/provisioning_api/lib/Controller/VerificationController.php
new file mode 100644
index 00000000000..70535c4906c
--- /dev/null
+++ b/apps/provisioning_api/lib/Controller/VerificationController.php
@@ -0,0 +1,125 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Provisioning_API\Controller;
+
+use InvalidArgumentException;
+use OC\Security\Crypto;
+use OCP\Accounts\IAccountManager;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\BruteForceProtection;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\Attribute\OpenAPI;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\IL10N;
+use OCP\IRequest;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use OCP\Security\VerificationToken\InvalidTokenException;
+use OCP\Security\VerificationToken\IVerificationToken;
+
+#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
+class VerificationController extends Controller {
+
+ /** @var Crypto */
+ private $crypto;
+
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private IVerificationToken $verificationToken,
+ private IUserManager $userManager,
+ private IL10N $l10n,
+ private IUserSession $userSession,
+ private IAccountManager $accountManager,
+ Crypto $crypto,
+ ) {
+ parent::__construct($appName, $request);
+ $this->crypto = $crypto;
+ }
+
+ /**
+ * @NoSubAdminRequired
+ */
+ #[NoAdminRequired]
+ #[NoCSRFRequired]
+ public function showVerifyMail(string $token, string $userId, string $key): TemplateResponse {
+ if ($this->userSession->getUser()->getUID() !== $userId) {
+ // not a public page, hence getUser() must return an IUser
+ throw new InvalidArgumentException('Logged in account is not mail address owner');
+ }
+ $email = $this->crypto->decrypt($key);
+
+ return new TemplateResponse(
+ 'core', 'confirmation', [
+ 'title' => $this->l10n->t('Email confirmation'),
+ 'message' => $this->l10n->t('To enable the email address %s please click the button below.', [$email]),
+ 'action' => $this->l10n->t('Confirm'),
+ ], TemplateResponse::RENDER_AS_GUEST);
+ }
+
+ /**
+ * @NoSubAdminRequired
+ */
+ #[NoAdminRequired]
+ #[BruteForceProtection(action: 'emailVerification')]
+ public function verifyMail(string $token, string $userId, string $key): TemplateResponse {
+ $throttle = false;
+ try {
+ if ($this->userSession->getUser()->getUID() !== $userId) {
+ throw new InvalidArgumentException('Logged in account is not mail address owner');
+ }
+ $email = $this->crypto->decrypt($key);
+ $ref = \substr(hash('sha256', $email), 0, 8);
+
+ $user = $this->userManager->get($userId);
+ $this->verificationToken->check($token, $user, 'verifyMail' . $ref, $email);
+
+ $userAccount = $this->accountManager->getAccount($user);
+ $emailProperty = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)
+ ->getPropertyByValue($email);
+
+ if ($emailProperty === null) {
+ throw new InvalidArgumentException($this->l10n->t('Email was already removed from account and cannot be confirmed anymore.'));
+ }
+ $emailProperty->setLocallyVerified(IAccountManager::VERIFIED);
+ $this->accountManager->updateAccount($userAccount);
+ $this->verificationToken->delete($token, $user, 'verifyMail' . $ref);
+ } catch (InvalidTokenException $e) {
+ if ($e->getCode() === InvalidTokenException::TOKEN_EXPIRED) {
+ $error = $this->l10n->t('Could not verify mail because the token is expired.');
+ } else {
+ $throttle = true;
+ $error = $this->l10n->t('Could not verify mail because the token is invalid.');
+ }
+ } catch (InvalidArgumentException $e) {
+ $error = $e->getMessage();
+ } catch (\Exception $e) {
+ $error = $this->l10n->t('An unexpected error occurred. Please contact your admin.');
+ }
+
+ if (isset($error)) {
+ $response = new TemplateResponse(
+ 'core', 'error', [
+ 'errors' => [['error' => $error]]
+ ], TemplateResponse::RENDER_AS_GUEST);
+ if ($throttle) {
+ $response->throttle();
+ }
+ return $response;
+ }
+
+ return new TemplateResponse(
+ 'core', 'success', [
+ 'title' => $this->l10n->t('Email confirmation successful'),
+ 'message' => $this->l10n->t('Email confirmation successful'),
+ ], TemplateResponse::RENDER_AS_GUEST);
+ }
+}
diff --git a/apps/provisioning_api/lib/FederatedShareProviderFactory.php b/apps/provisioning_api/lib/FederatedShareProviderFactory.php
new file mode 100644
index 00000000000..3da76102c4a
--- /dev/null
+++ b/apps/provisioning_api/lib/FederatedShareProviderFactory.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Provisioning_API;
+
+use OCA\FederatedFileSharing\FederatedShareProvider;
+use OCP\IServerContainer;
+
+class FederatedShareProviderFactory {
+
+ public function __construct(
+ private IServerContainer $serverContainer,
+ ) {
+ }
+
+ public function get(): FederatedShareProvider {
+ return $this->serverContainer->query(FederatedShareProvider::class);
+ }
+}
diff --git a/apps/provisioning_api/lib/Listener/UserDeletedListener.php b/apps/provisioning_api/lib/Listener/UserDeletedListener.php
new file mode 100644
index 00000000000..099b5593ed7
--- /dev/null
+++ b/apps/provisioning_api/lib/Listener/UserDeletedListener.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Provisioning_API\Listener;
+
+use OC\KnownUser\KnownUserService;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\UserDeletedEvent;
+
+/** @template-implements IEventListener<UserDeletedEvent> */
+class UserDeletedListener implements IEventListener {
+
+ /** @var KnownUserService */
+ private $service;
+
+ public function __construct(KnownUserService $service) {
+ $this->service = $service;
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof UserDeletedEvent)) {
+ // Unrelated
+ return;
+ }
+
+ $user = $event->getUser();
+
+ // Delete all entries of this user
+ $this->service->deleteKnownTo($user->getUID());
+
+ // Delete all entries that other users know this user
+ $this->service->deleteByContactUserId($user->getUID());
+ }
+}
diff --git a/apps/provisioning_api/lib/Middleware/Exceptions/NotSubAdminException.php b/apps/provisioning_api/lib/Middleware/Exceptions/NotSubAdminException.php
index 11ffb8b0903..b014d6a1495 100644
--- a/apps/provisioning_api/lib/Middleware/Exceptions/NotSubAdminException.php
+++ b/apps/provisioning_api/lib/Middleware/Exceptions/NotSubAdminException.php
@@ -1,25 +1,8 @@
<?php
+
/**
- *
- *
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Provisioning_API\Middleware\Exceptions;
@@ -27,6 +10,6 @@ use OCP\AppFramework\Http;
class NotSubAdminException extends \Exception {
public function __construct() {
- parent::__construct('Logged in user must be at least a sub admin', Http::STATUS_FORBIDDEN);
+ parent::__construct('Logged in account must be at least a sub admin', Http::STATUS_FORBIDDEN);
}
-} \ No newline at end of file
+}
diff --git a/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php b/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php
index 4c7f7a654c8..1989ef5d4c1 100644
--- a/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php
+++ b/apps/provisioning_api/lib/Middleware/ProvisioningApiMiddleware.php
@@ -1,31 +1,16 @@
<?php
+
+declare(strict_types=1);
+
/**
- *
- *
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Provisioning_API\Middleware;
use OCA\Provisioning_API\Middleware\Exceptions\NotSubAdminException;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\OCS\OCSException;
@@ -33,15 +18,6 @@ use OCP\AppFramework\Utility\IControllerMethodReflector;
class ProvisioningApiMiddleware extends Middleware {
- /** @var IControllerMethodReflector */
- private $reflector;
-
- /** @var bool */
- private $isAdmin;
-
- /** @var bool */
- private $isSubAdmin;
-
/**
* ProvisioningApiMiddleware constructor.
*
@@ -50,12 +26,10 @@ class ProvisioningApiMiddleware extends Middleware {
* @param bool $isSubAdmin
*/
public function __construct(
- IControllerMethodReflector $reflector,
- $isAdmin,
- $isSubAdmin) {
- $this->reflector = $reflector;
- $this->isAdmin = $isAdmin;
- $this->isSubAdmin = $isSubAdmin;
+ private IControllerMethodReflector $reflector,
+ private bool $isAdmin,
+ private bool $isSubAdmin,
+ ) {
}
/**
@@ -65,7 +39,8 @@ class ProvisioningApiMiddleware extends Middleware {
* @throws NotSubAdminException
*/
public function beforeController($controller, $methodName) {
- if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin) {
+ // If AuthorizedAdminSetting, the check will be done in the SecurityMiddleware
+ if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin && !$this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
throw new NotSubAdminException();
}
}
@@ -79,7 +54,7 @@ class ProvisioningApiMiddleware extends Middleware {
*/
public function afterException($controller, $methodName, \Exception $exception) {
if ($exception instanceof NotSubAdminException) {
- throw new OCSException($exception->getMessage(), \OCP\API::RESPOND_UNAUTHORISED);
+ throw new OCSException($exception->getMessage(), Http::STATUS_FORBIDDEN);
}
throw $exception;
diff --git a/apps/provisioning_api/lib/ResponseDefinitions.php b/apps/provisioning_api/lib/ResponseDefinitions.php
new file mode 100644
index 00000000000..62ae4ca577b
--- /dev/null
+++ b/apps/provisioning_api/lib/ResponseDefinitions.php
@@ -0,0 +1,86 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Provisioning_API;
+
+/**
+ * @psalm-type Provisioning_APIUserDetailsQuota = array{
+ * free?: float|int,
+ * quota?: float|int|string,
+ * relative?: float|int,
+ * total?: float|int,
+ * used?: float|int,
+ * }
+ *
+ * @psalm-type Provisioning_APIUserDetailsScope = 'v2-private'|'v2-local'|'v2-federated'|'v2-published'|'private'|'contacts'|'public'
+ *
+ * @psalm-type Provisioning_APIUserDetails = array{
+ * additional_mail: list<string>,
+ * additional_mailScope?: list<Provisioning_APIUserDetailsScope>,
+ * address: string,
+ * addressScope?: Provisioning_APIUserDetailsScope,
+ * avatarScope?: Provisioning_APIUserDetailsScope,
+ * backend: string,
+ * backendCapabilities: array{
+ * setDisplayName: bool,
+ * setPassword: bool
+ * },
+ * biography: string,
+ * biographyScope?: Provisioning_APIUserDetailsScope,
+ * display-name: string,
+ * displayname: string,
+ * displaynameScope?: Provisioning_APIUserDetailsScope,
+ * email: ?string,
+ * emailScope?: Provisioning_APIUserDetailsScope,
+ * enabled?: bool,
+ * fediverse: string,
+ * fediverseScope?: Provisioning_APIUserDetailsScope,
+ * groups: list<string>,
+ * headline: string,
+ * headlineScope?: Provisioning_APIUserDetailsScope,
+ * id: string,
+ * language: string,
+ * firstLoginTimestamp: int,
+ * lastLoginTimestamp: int,
+ * lastLogin: int,
+ * locale: string,
+ * manager: string,
+ * notify_email: ?string,
+ * organisation: string,
+ * organisationScope?: Provisioning_APIUserDetailsScope,
+ * phone: string,
+ * phoneScope?: Provisioning_APIUserDetailsScope,
+ * profile_enabled: string,
+ * profile_enabledScope?: Provisioning_APIUserDetailsScope,
+ * pronouns: string,
+ * pronounsScope?: Provisioning_APIUserDetailsScope,
+ * quota: Provisioning_APIUserDetailsQuota,
+ * role: string,
+ * roleScope?: Provisioning_APIUserDetailsScope,
+ * storageLocation?: string,
+ * subadmin: list<string>,
+ * twitter: string,
+ * twitterScope?: Provisioning_APIUserDetailsScope,
+ * bluesky: string,
+ * blueskyScope?: Provisioning_APIUserDetailsScope,
+ * website: string,
+ * websiteScope?: Provisioning_APIUserDetailsScope,
+ * }
+ *
+ * @psalm-type Provisioning_APIGroupDetails = array{
+ * id: string,
+ * displayname: string,
+ * usercount: bool|int,
+ * disabled: bool|int,
+ * canAdd: bool,
+ * canRemove: bool,
+ * }
+ */
+class ResponseDefinitions {
+}
diff --git a/apps/provisioning_api/openapi-administration.json b/apps/provisioning_api/openapi-administration.json
new file mode 100644
index 00000000000..08bba7a05a1
--- /dev/null
+++ b/apps/provisioning_api/openapi-administration.json
@@ -0,0 +1,1803 @@
+{
+ "openapi": "3.0.3",
+ "info": {
+ "title": "provisioning_api-administration",
+ "version": "0.0.1",
+ "description": "This application enables a set of APIs that external systems can use to manage accounts, groups and apps.",
+ "license": {
+ "name": "agpl"
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "basic_auth": {
+ "type": "http",
+ "scheme": "basic"
+ },
+ "bearer_auth": {
+ "type": "http",
+ "scheme": "bearer"
+ }
+ },
+ "schemas": {
+ "Capabilities": {
+ "type": "object",
+ "required": [
+ "provisioning_api"
+ ],
+ "properties": {
+ "provisioning_api": {
+ "type": "object",
+ "required": [
+ "version",
+ "AccountPropertyScopesVersion",
+ "AccountPropertyScopesFederatedEnabled",
+ "AccountPropertyScopesPublishedEnabled"
+ ],
+ "properties": {
+ "version": {
+ "type": "string"
+ },
+ "AccountPropertyScopesVersion": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "AccountPropertyScopesFederatedEnabled": {
+ "type": "boolean"
+ },
+ "AccountPropertyScopesPublishedEnabled": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ },
+ "OCSMeta": {
+ "type": "object",
+ "required": [
+ "status",
+ "statuscode"
+ ],
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "statuscode": {
+ "type": "integer"
+ },
+ "message": {
+ "type": "string"
+ },
+ "totalitems": {
+ "type": "string"
+ },
+ "itemsperpage": {
+ "type": "string"
+ }
+ }
+ },
+ "UserDetails": {
+ "type": "object",
+ "required": [
+ "additional_mail",
+ "address",
+ "backend",
+ "backendCapabilities",
+ "biography",
+ "display-name",
+ "displayname",
+ "email",
+ "fediverse",
+ "groups",
+ "headline",
+ "id",
+ "language",
+ "firstLoginTimestamp",
+ "lastLoginTimestamp",
+ "lastLogin",
+ "locale",
+ "manager",
+ "notify_email",
+ "organisation",
+ "phone",
+ "profile_enabled",
+ "pronouns",
+ "quota",
+ "role",
+ "subadmin",
+ "twitter",
+ "bluesky",
+ "website"
+ ],
+ "properties": {
+ "additional_mail": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "additional_mailScope": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ }
+ },
+ "address": {
+ "type": "string"
+ },
+ "addressScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "avatarScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "backend": {
+ "type": "string"
+ },
+ "backendCapabilities": {
+ "type": "object",
+ "required": [
+ "setDisplayName",
+ "setPassword"
+ ],
+ "properties": {
+ "setDisplayName": {
+ "type": "boolean"
+ },
+ "setPassword": {
+ "type": "boolean"
+ }
+ }
+ },
+ "biography": {
+ "type": "string"
+ },
+ "biographyScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "display-name": {
+ "type": "string"
+ },
+ "displayname": {
+ "type": "string"
+ },
+ "displaynameScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "email": {
+ "type": "string",
+ "nullable": true
+ },
+ "emailScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "fediverse": {
+ "type": "string"
+ },
+ "fediverseScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "headline": {
+ "type": "string"
+ },
+ "headlineScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "id": {
+ "type": "string"
+ },
+ "language": {
+ "type": "string"
+ },
+ "firstLoginTimestamp": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "lastLoginTimestamp": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "lastLogin": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "locale": {
+ "type": "string"
+ },
+ "manager": {
+ "type": "string"
+ },
+ "notify_email": {
+ "type": "string",
+ "nullable": true
+ },
+ "organisation": {
+ "type": "string"
+ },
+ "organisationScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "phone": {
+ "type": "string"
+ },
+ "phoneScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "profile_enabled": {
+ "type": "string"
+ },
+ "profile_enabledScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "pronouns": {
+ "type": "string"
+ },
+ "pronounsScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "quota": {
+ "$ref": "#/components/schemas/UserDetailsQuota"
+ },
+ "role": {
+ "type": "string"
+ },
+ "roleScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "storageLocation": {
+ "type": "string"
+ },
+ "subadmin": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "twitter": {
+ "type": "string"
+ },
+ "twitterScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "bluesky": {
+ "type": "string"
+ },
+ "blueskyScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "website": {
+ "type": "string"
+ },
+ "websiteScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ }
+ }
+ },
+ "UserDetailsQuota": {
+ "type": "object",
+ "properties": {
+ "free": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "quota": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "relative": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "total": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "used": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ }
+ }
+ },
+ "UserDetailsScope": {
+ "type": "string",
+ "enum": [
+ "v2-private",
+ "v2-local",
+ "v2-federated",
+ "v2-published",
+ "private",
+ "contacts",
+ "public"
+ ]
+ }
+ }
+ },
+ "paths": {
+ "/ocs/v2.php/cloud/apps": {
+ "get": {
+ "operationId": "apps-get-apps",
+ "summary": "Get a list of installed apps",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "filter",
+ "in": "query",
+ "description": "Filter for enabled or disabled apps",
+ "schema": {
+ "type": "string",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Installed apps returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "apps"
+ ],
+ "properties": {
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/apps/{app}": {
+ "get": {
+ "operationId": "apps-get-app-info",
+ "summary": "Get the app info for an app",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "App info returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "apps-enable",
+ "summary": "Enable an app",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "App enabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "apps-disable",
+ "summary": "Disable an app",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "App disabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}/subadmins": {
+ "get": {
+ "operationId": "groups-get-sub-admins-of-group",
+ "summary": "Get the list of user IDs that are a subadmin of the group",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Sub admins returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups": {
+ "post": {
+ "operationId": "groups-add-group",
+ "summary": "Create a new group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "groupid"
+ ],
+ "properties": {
+ "groupid": {
+ "type": "string",
+ "description": "ID of the group"
+ },
+ "displayname": {
+ "type": "string",
+ "default": "",
+ "description": "Display name of the group"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group created successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}": {
+ "put": {
+ "operationId": "groups-update-group",
+ "summary": "Update a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "Key to update, only 'displayname'"
+ },
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "groups-delete-group",
+ "summary": "Delete a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/recent": {
+ "get": {
+ "operationId": "users-get-last-logged-in-users",
+ "summary": "Gets the list of users sorted by lastLogin, from most recent to least recent",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of users returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users details returned based on last logged in information",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/subadmins": {
+ "get": {
+ "operationId": "users-get-user-sub-admin-groups",
+ "summary": "Get the groups a user is a subadmin of",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID if the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User subadmin groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "users-add-sub-admin",
+ "summary": "Make a user a subadmin of a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "groupid"
+ ],
+ "properties": {
+ "groupid": {
+ "type": "string",
+ "description": "ID of the group"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User added as group subadmin successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "users-remove-sub-admin",
+ "summary": "Remove a user from the subadmins of a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "groupid",
+ "in": "query",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User removed as group subadmin successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps": {
+ "get": {
+ "operationId": "app_config-get-apps",
+ "summary": "Get a list of apps",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Apps returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps/{app}": {
+ "get": {
+ "operationId": "app_config-get-keys",
+ "summary": "Get the config keys of an app",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Keys returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps/{app}/{key}": {
+ "get": {
+ "operationId": "app_config-get-value",
+ "summary": "Get a the config value of an app",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "key",
+ "in": "path",
+ "description": "Key",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "defaultValue",
+ "in": "query",
+ "description": "Default returned value if the value is empty",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Value returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "app_config-delete-key",
+ "summary": "Delete a config key of an app",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "key",
+ "in": "path",
+ "description": "Key to delete",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Key deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App or key is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/apps/provisioning_api/openapi-administration.json.license b/apps/provisioning_api/openapi-administration.json.license
new file mode 100644
index 00000000000..5dcb9c9e84b
--- /dev/null
+++ b/apps/provisioning_api/openapi-administration.json.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file
diff --git a/apps/provisioning_api/openapi-full.json b/apps/provisioning_api/openapi-full.json
new file mode 100644
index 00000000000..3684e7cbc41
--- /dev/null
+++ b/apps/provisioning_api/openapi-full.json
@@ -0,0 +1,4890 @@
+{
+ "openapi": "3.0.3",
+ "info": {
+ "title": "provisioning_api-full",
+ "version": "0.0.1",
+ "description": "This application enables a set of APIs that external systems can use to manage accounts, groups and apps.",
+ "license": {
+ "name": "agpl"
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "basic_auth": {
+ "type": "http",
+ "scheme": "basic"
+ },
+ "bearer_auth": {
+ "type": "http",
+ "scheme": "bearer"
+ }
+ },
+ "schemas": {
+ "Capabilities": {
+ "type": "object",
+ "required": [
+ "provisioning_api"
+ ],
+ "properties": {
+ "provisioning_api": {
+ "type": "object",
+ "required": [
+ "version",
+ "AccountPropertyScopesVersion",
+ "AccountPropertyScopesFederatedEnabled",
+ "AccountPropertyScopesPublishedEnabled"
+ ],
+ "properties": {
+ "version": {
+ "type": "string"
+ },
+ "AccountPropertyScopesVersion": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "AccountPropertyScopesFederatedEnabled": {
+ "type": "boolean"
+ },
+ "AccountPropertyScopesPublishedEnabled": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ },
+ "GroupDetails": {
+ "type": "object",
+ "required": [
+ "id",
+ "displayname",
+ "usercount",
+ "disabled",
+ "canAdd",
+ "canRemove"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "displayname": {
+ "type": "string"
+ },
+ "usercount": {
+ "oneOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "disabled": {
+ "oneOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "canAdd": {
+ "type": "boolean"
+ },
+ "canRemove": {
+ "type": "boolean"
+ }
+ }
+ },
+ "OCSMeta": {
+ "type": "object",
+ "required": [
+ "status",
+ "statuscode"
+ ],
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "statuscode": {
+ "type": "integer"
+ },
+ "message": {
+ "type": "string"
+ },
+ "totalitems": {
+ "type": "string"
+ },
+ "itemsperpage": {
+ "type": "string"
+ }
+ }
+ },
+ "UserDetails": {
+ "type": "object",
+ "required": [
+ "additional_mail",
+ "address",
+ "backend",
+ "backendCapabilities",
+ "biography",
+ "display-name",
+ "displayname",
+ "email",
+ "fediverse",
+ "groups",
+ "headline",
+ "id",
+ "language",
+ "firstLoginTimestamp",
+ "lastLoginTimestamp",
+ "lastLogin",
+ "locale",
+ "manager",
+ "notify_email",
+ "organisation",
+ "phone",
+ "profile_enabled",
+ "pronouns",
+ "quota",
+ "role",
+ "subadmin",
+ "twitter",
+ "bluesky",
+ "website"
+ ],
+ "properties": {
+ "additional_mail": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "additional_mailScope": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ }
+ },
+ "address": {
+ "type": "string"
+ },
+ "addressScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "avatarScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "backend": {
+ "type": "string"
+ },
+ "backendCapabilities": {
+ "type": "object",
+ "required": [
+ "setDisplayName",
+ "setPassword"
+ ],
+ "properties": {
+ "setDisplayName": {
+ "type": "boolean"
+ },
+ "setPassword": {
+ "type": "boolean"
+ }
+ }
+ },
+ "biography": {
+ "type": "string"
+ },
+ "biographyScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "display-name": {
+ "type": "string"
+ },
+ "displayname": {
+ "type": "string"
+ },
+ "displaynameScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "email": {
+ "type": "string",
+ "nullable": true
+ },
+ "emailScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "fediverse": {
+ "type": "string"
+ },
+ "fediverseScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "headline": {
+ "type": "string"
+ },
+ "headlineScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "id": {
+ "type": "string"
+ },
+ "language": {
+ "type": "string"
+ },
+ "firstLoginTimestamp": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "lastLoginTimestamp": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "lastLogin": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "locale": {
+ "type": "string"
+ },
+ "manager": {
+ "type": "string"
+ },
+ "notify_email": {
+ "type": "string",
+ "nullable": true
+ },
+ "organisation": {
+ "type": "string"
+ },
+ "organisationScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "phone": {
+ "type": "string"
+ },
+ "phoneScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "profile_enabled": {
+ "type": "string"
+ },
+ "profile_enabledScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "pronouns": {
+ "type": "string"
+ },
+ "pronounsScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "quota": {
+ "$ref": "#/components/schemas/UserDetailsQuota"
+ },
+ "role": {
+ "type": "string"
+ },
+ "roleScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "storageLocation": {
+ "type": "string"
+ },
+ "subadmin": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "twitter": {
+ "type": "string"
+ },
+ "twitterScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "bluesky": {
+ "type": "string"
+ },
+ "blueskyScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "website": {
+ "type": "string"
+ },
+ "websiteScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ }
+ }
+ },
+ "UserDetailsQuota": {
+ "type": "object",
+ "properties": {
+ "free": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "quota": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "relative": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "total": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "used": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ }
+ }
+ },
+ "UserDetailsScope": {
+ "type": "string",
+ "enum": [
+ "v2-private",
+ "v2-local",
+ "v2-federated",
+ "v2-published",
+ "private",
+ "contacts",
+ "public"
+ ]
+ }
+ }
+ },
+ "paths": {
+ "/ocs/v2.php/cloud/apps": {
+ "get": {
+ "operationId": "apps-get-apps",
+ "summary": "Get a list of installed apps",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "filter",
+ "in": "query",
+ "description": "Filter for enabled or disabled apps",
+ "schema": {
+ "type": "string",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Installed apps returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "apps"
+ ],
+ "properties": {
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/apps/{app}": {
+ "get": {
+ "operationId": "apps-get-app-info",
+ "summary": "Get the app info for an app",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "App info returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "apps-enable",
+ "summary": "Enable an app",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "App enabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "apps-disable",
+ "summary": "Disable an app",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "apps"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "App disabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}/subadmins": {
+ "get": {
+ "operationId": "groups-get-sub-admins-of-group",
+ "summary": "Get the list of user IDs that are a subadmin of the group",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Sub admins returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups": {
+ "post": {
+ "operationId": "groups-add-group",
+ "summary": "Create a new group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "groupid"
+ ],
+ "properties": {
+ "groupid": {
+ "type": "string",
+ "description": "ID of the group"
+ },
+ "displayname": {
+ "type": "string",
+ "default": "",
+ "description": "Display name of the group"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group created successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "operationId": "groups-get-groups",
+ "summary": "Get a list of groups",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}": {
+ "put": {
+ "operationId": "groups-update-group",
+ "summary": "Update a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "Key to update, only 'displayname'"
+ },
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "groups-delete-group",
+ "summary": "Delete a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "operationId": "groups-get-group",
+ "summary": "Get a list of users in the specified group",
+ "deprecated": true,
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group users returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/recent": {
+ "get": {
+ "operationId": "users-get-last-logged-in-users",
+ "summary": "Gets the list of users sorted by lastLogin, from most recent to least recent",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of users returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users details returned based on last logged in information",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/subadmins": {
+ "get": {
+ "operationId": "users-get-user-sub-admin-groups",
+ "summary": "Get the groups a user is a subadmin of",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID if the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User subadmin groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "users-add-sub-admin",
+ "summary": "Make a user a subadmin of a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "groupid"
+ ],
+ "properties": {
+ "groupid": {
+ "type": "string",
+ "description": "ID of the group"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User added as group subadmin successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "users-remove-sub-admin",
+ "summary": "Remove a user from the subadmins of a group",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "groupid",
+ "in": "query",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User removed as group subadmin successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps": {
+ "get": {
+ "operationId": "app_config-get-apps",
+ "summary": "Get a list of apps",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Apps returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps/{app}": {
+ "get": {
+ "operationId": "app_config-get-keys",
+ "summary": "Get the config keys of an app",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Keys returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps/{app}/{key}": {
+ "get": {
+ "operationId": "app_config-get-value",
+ "summary": "Get a the config value of an app",
+ "description": "This endpoint requires admin access",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "key",
+ "in": "path",
+ "description": "Key",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "defaultValue",
+ "in": "query",
+ "description": "Default returned value if the value is empty",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Value returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "app_config-delete-key",
+ "summary": "Delete a config key of an app",
+ "description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "key",
+ "in": "path",
+ "description": "Key to delete",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Key deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App or key is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "app_config-set-value",
+ "summary": "Update the config value of an app",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "value"
+ ],
+ "properties": {
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "key",
+ "in": "path",
+ "description": "Key to update",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Value updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App or key is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/details": {
+ "get": {
+ "operationId": "groups-get-groups-details",
+ "summary": "Get a list of groups details",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Groups details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GroupDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}/users": {
+ "get": {
+ "operationId": "groups-get-group-users",
+ "summary": "Get a list of users in the specified group",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User IDs returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Group not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Missing permissions to get users in the group",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}/users/details": {
+ "get": {
+ "operationId": "groups-get-group-users-details",
+ "summary": "Get a list of users details in the specified group",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group users details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users": {
+ "get": {
+ "operationId": "users-get-users",
+ "summary": "Get a list of users",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "users-add-user",
+ "summary": "Create a new user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "userid"
+ ],
+ "properties": {
+ "userid": {
+ "type": "string",
+ "description": "ID of the user"
+ },
+ "password": {
+ "type": "string",
+ "default": "",
+ "description": "Password of the user"
+ },
+ "displayName": {
+ "type": "string",
+ "default": "",
+ "description": "Display name of the user"
+ },
+ "email": {
+ "type": "string",
+ "default": "",
+ "description": "Email of the user"
+ },
+ "groups": {
+ "type": "array",
+ "default": [],
+ "description": "Groups of the user",
+ "items": {
+ "type": "string"
+ }
+ },
+ "subadmin": {
+ "type": "array",
+ "default": [],
+ "description": "Groups where the user is subadmin",
+ "items": {
+ "type": "string"
+ }
+ },
+ "quota": {
+ "type": "string",
+ "default": "",
+ "description": "Quota of the user"
+ },
+ "language": {
+ "type": "string",
+ "default": "",
+ "description": "Language of the user"
+ },
+ "manager": {
+ "type": "string",
+ "nullable": true,
+ "default": null,
+ "description": "Manager of the user"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User added successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Missing permissions to make user subadmin",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/details": {
+ "get": {
+ "operationId": "users-get-users-details",
+ "summary": "Get a list of users and their details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/disabled": {
+ "get": {
+ "operationId": "users-get-disabled-users-details",
+ "summary": "Get the list of disabled users and their details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of users returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Disabled users details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/search/by-phone": {
+ "post": {
+ "operationId": "users-search-by-phone-numbers",
+ "summary": "Search users by their phone numbers",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "location",
+ "search"
+ ],
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "Location of the phone number (for country code)"
+ },
+ "search": {
+ "type": "object",
+ "description": "Phone numbers to search for",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid location",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}": {
+ "get": {
+ "operationId": "users-get-user",
+ "summary": "Get the details of a user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/UserDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "operationId": "users-edit-user",
+ "summary": "Update a value of the user's details",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "Key that will be updated"
+ },
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User value edited successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "users-delete-user",
+ "summary": "Delete a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user": {
+ "get": {
+ "operationId": "users-get-current-user",
+ "summary": "Get the details of the current user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Current user returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/UserDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user/fields": {
+ "get": {
+ "operationId": "users-get-editable-fields",
+ "summary": "Get a list of fields that are editable for the current user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Editable fields returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user/fields/{userId}": {
+ "get": {
+ "operationId": "users-get-editable-fields-for-user",
+ "summary": "Get a list of fields that are editable for a user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Editable fields for user returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user/apps": {
+ "get": {
+ "operationId": "users-get-enabled-apps",
+ "summary": "Get a list of enabled apps for the current user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Enabled apps returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "apps"
+ ],
+ "properties": {
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/{collectionName}": {
+ "put": {
+ "operationId": "users-edit-user-multi-value",
+ "summary": "Update multiple values of the user's details",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "Key that will be updated"
+ },
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "collectionName",
+ "in": "path",
+ "description": "Collection to update",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^(?!enable$|disable$)[a-zA-Z0-9_]*$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User values edited successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/wipe": {
+ "post": {
+ "operationId": "users-wipe-user-devices",
+ "summary": "Wipe all devices of a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Wiped all user devices successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/enable": {
+ "put": {
+ "operationId": "users-enable-user",
+ "summary": "Enable a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User enabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/disable": {
+ "put": {
+ "operationId": "users-disable-user",
+ "summary": "Disable a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User disabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/groups": {
+ "get": {
+ "operationId": "users-get-users-groups",
+ "summary": "Get a list of groups the user belongs to",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "users-add-to-group",
+ "summary": "Add a user to a group",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "groupid": {
+ "type": "string",
+ "default": "",
+ "description": "ID of the group"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User added to group successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "users-remove-from-group",
+ "summary": "Remove a user from a group",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "groupid",
+ "in": "query",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User removed from group successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/groups/details": {
+ "get": {
+ "operationId": "users-get-users-groups-details",
+ "summary": "Get a list of groups with details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GroupDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/subadmins/details": {
+ "get": {
+ "operationId": "users-get-user-sub-admin-groups-details",
+ "summary": "Get a list of the groups the user is a subadmin of, with details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users subadmin groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GroupDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/welcome": {
+ "post": {
+ "operationId": "users-resend-welcome-message",
+ "summary": "Resend the welcome message",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID if the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Resent welcome message successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/users/{appId}/{configKey}": {
+ "post": {
+ "operationId": "preferences-set-preference",
+ "summary": "Update a preference value of an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "configValue"
+ ],
+ "properties": {
+ "configValue": {
+ "type": "string",
+ "description": "New value"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "configKey",
+ "in": "path",
+ "description": "Key of the preference",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preference updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "preferences-delete-preference",
+ "summary": "Delete a preference for an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "configKey",
+ "in": "path",
+ "description": "Key to delete",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preference deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/users/{appId}": {
+ "post": {
+ "operationId": "preferences-set-multiple-preferences",
+ "summary": "Update multiple preference values of an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "configs"
+ ],
+ "properties": {
+ "configs": {
+ "type": "object",
+ "description": "Key-value pairs of the preferences",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preferences updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "preferences-delete-multiple-preference",
+ "summary": "Delete multiple preferences for an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "configKeys[]",
+ "in": "query",
+ "description": "Keys to delete",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preferences deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/apps/provisioning_api/openapi-full.json.license b/apps/provisioning_api/openapi-full.json.license
new file mode 100644
index 00000000000..5dcb9c9e84b
--- /dev/null
+++ b/apps/provisioning_api/openapi-full.json.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file
diff --git a/apps/provisioning_api/openapi.json b/apps/provisioning_api/openapi.json
new file mode 100644
index 00000000000..cec2f7f86f1
--- /dev/null
+++ b/apps/provisioning_api/openapi.json
@@ -0,0 +1,3463 @@
+{
+ "openapi": "3.0.3",
+ "info": {
+ "title": "provisioning_api",
+ "version": "0.0.1",
+ "description": "This application enables a set of APIs that external systems can use to manage accounts, groups and apps.",
+ "license": {
+ "name": "agpl"
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "basic_auth": {
+ "type": "http",
+ "scheme": "basic"
+ },
+ "bearer_auth": {
+ "type": "http",
+ "scheme": "bearer"
+ }
+ },
+ "schemas": {
+ "Capabilities": {
+ "type": "object",
+ "required": [
+ "provisioning_api"
+ ],
+ "properties": {
+ "provisioning_api": {
+ "type": "object",
+ "required": [
+ "version",
+ "AccountPropertyScopesVersion",
+ "AccountPropertyScopesFederatedEnabled",
+ "AccountPropertyScopesPublishedEnabled"
+ ],
+ "properties": {
+ "version": {
+ "type": "string"
+ },
+ "AccountPropertyScopesVersion": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "AccountPropertyScopesFederatedEnabled": {
+ "type": "boolean"
+ },
+ "AccountPropertyScopesPublishedEnabled": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ },
+ "GroupDetails": {
+ "type": "object",
+ "required": [
+ "id",
+ "displayname",
+ "usercount",
+ "disabled",
+ "canAdd",
+ "canRemove"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "displayname": {
+ "type": "string"
+ },
+ "usercount": {
+ "oneOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "disabled": {
+ "oneOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "canAdd": {
+ "type": "boolean"
+ },
+ "canRemove": {
+ "type": "boolean"
+ }
+ }
+ },
+ "OCSMeta": {
+ "type": "object",
+ "required": [
+ "status",
+ "statuscode"
+ ],
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "statuscode": {
+ "type": "integer"
+ },
+ "message": {
+ "type": "string"
+ },
+ "totalitems": {
+ "type": "string"
+ },
+ "itemsperpage": {
+ "type": "string"
+ }
+ }
+ },
+ "UserDetails": {
+ "type": "object",
+ "required": [
+ "additional_mail",
+ "address",
+ "backend",
+ "backendCapabilities",
+ "biography",
+ "display-name",
+ "displayname",
+ "email",
+ "fediverse",
+ "groups",
+ "headline",
+ "id",
+ "language",
+ "firstLoginTimestamp",
+ "lastLoginTimestamp",
+ "lastLogin",
+ "locale",
+ "manager",
+ "notify_email",
+ "organisation",
+ "phone",
+ "profile_enabled",
+ "pronouns",
+ "quota",
+ "role",
+ "subadmin",
+ "twitter",
+ "bluesky",
+ "website"
+ ],
+ "properties": {
+ "additional_mail": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "additional_mailScope": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ }
+ },
+ "address": {
+ "type": "string"
+ },
+ "addressScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "avatarScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "backend": {
+ "type": "string"
+ },
+ "backendCapabilities": {
+ "type": "object",
+ "required": [
+ "setDisplayName",
+ "setPassword"
+ ],
+ "properties": {
+ "setDisplayName": {
+ "type": "boolean"
+ },
+ "setPassword": {
+ "type": "boolean"
+ }
+ }
+ },
+ "biography": {
+ "type": "string"
+ },
+ "biographyScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "display-name": {
+ "type": "string"
+ },
+ "displayname": {
+ "type": "string"
+ },
+ "displaynameScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "email": {
+ "type": "string",
+ "nullable": true
+ },
+ "emailScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "fediverse": {
+ "type": "string"
+ },
+ "fediverseScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "headline": {
+ "type": "string"
+ },
+ "headlineScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "id": {
+ "type": "string"
+ },
+ "language": {
+ "type": "string"
+ },
+ "firstLoginTimestamp": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "lastLoginTimestamp": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "lastLogin": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "locale": {
+ "type": "string"
+ },
+ "manager": {
+ "type": "string"
+ },
+ "notify_email": {
+ "type": "string",
+ "nullable": true
+ },
+ "organisation": {
+ "type": "string"
+ },
+ "organisationScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "phone": {
+ "type": "string"
+ },
+ "phoneScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "profile_enabled": {
+ "type": "string"
+ },
+ "profile_enabledScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "pronouns": {
+ "type": "string"
+ },
+ "pronounsScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "quota": {
+ "$ref": "#/components/schemas/UserDetailsQuota"
+ },
+ "role": {
+ "type": "string"
+ },
+ "roleScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "storageLocation": {
+ "type": "string"
+ },
+ "subadmin": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "twitter": {
+ "type": "string"
+ },
+ "twitterScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "bluesky": {
+ "type": "string"
+ },
+ "blueskyScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ },
+ "website": {
+ "type": "string"
+ },
+ "websiteScope": {
+ "$ref": "#/components/schemas/UserDetailsScope"
+ }
+ }
+ },
+ "UserDetailsQuota": {
+ "type": "object",
+ "properties": {
+ "free": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "quota": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "relative": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "total": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
+ "used": {
+ "anyOf": [
+ {
+ "type": "number",
+ "format": "double"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ }
+ }
+ },
+ "UserDetailsScope": {
+ "type": "string",
+ "enum": [
+ "v2-private",
+ "v2-local",
+ "v2-federated",
+ "v2-published",
+ "private",
+ "contacts",
+ "public"
+ ]
+ }
+ }
+ },
+ "paths": {
+ "/ocs/v2.php/cloud/groups": {
+ "get": {
+ "operationId": "groups-get-groups",
+ "summary": "Get a list of groups",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/details": {
+ "get": {
+ "operationId": "groups-get-groups-details",
+ "summary": "Get a list of groups details",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Groups details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GroupDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}/users": {
+ "get": {
+ "operationId": "groups-get-group-users",
+ "summary": "Get a list of users in the specified group",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User IDs returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Group not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Missing permissions to get users in the group",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}/users/details": {
+ "get": {
+ "operationId": "groups-get-group-users-details",
+ "summary": "Get a list of users details in the specified group",
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group users details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/groups/{groupId}": {
+ "get": {
+ "operationId": "groups-get-group",
+ "summary": "Get a list of users in the specified group",
+ "deprecated": true,
+ "tags": [
+ "groups"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "groupId",
+ "in": "path",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^.+$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Group users returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users": {
+ "get": {
+ "operationId": "users-get-users",
+ "summary": "Get a list of users",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "users-add-user",
+ "summary": "Create a new user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "userid"
+ ],
+ "properties": {
+ "userid": {
+ "type": "string",
+ "description": "ID of the user"
+ },
+ "password": {
+ "type": "string",
+ "default": "",
+ "description": "Password of the user"
+ },
+ "displayName": {
+ "type": "string",
+ "default": "",
+ "description": "Display name of the user"
+ },
+ "email": {
+ "type": "string",
+ "default": "",
+ "description": "Email of the user"
+ },
+ "groups": {
+ "type": "array",
+ "default": [],
+ "description": "Groups of the user",
+ "items": {
+ "type": "string"
+ }
+ },
+ "subadmin": {
+ "type": "array",
+ "default": [],
+ "description": "Groups where the user is subadmin",
+ "items": {
+ "type": "string"
+ }
+ },
+ "quota": {
+ "type": "string",
+ "default": "",
+ "description": "Quota of the user"
+ },
+ "language": {
+ "type": "string",
+ "default": "",
+ "description": "Language of the user"
+ },
+ "manager": {
+ "type": "string",
+ "nullable": true,
+ "default": null,
+ "description": "Manager of the user"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User added successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Missing permissions to make user subadmin",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/details": {
+ "get": {
+ "operationId": "users-get-users-details",
+ "summary": "Get a list of users and their details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of groups returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset for searching for groups",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/disabled": {
+ "get": {
+ "operationId": "users-get-disabled-users-details",
+ "summary": "Get the list of disabled users and their details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "description": "Text to search for",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Limit the amount of users returned",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "nullable": true,
+ "default": null
+ }
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Offset",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 0
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Disabled users details returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "users"
+ ],
+ "properties": {
+ "users": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/UserDetails"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/search/by-phone": {
+ "post": {
+ "operationId": "users-search-by-phone-numbers",
+ "summary": "Search users by their phone numbers",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "location",
+ "search"
+ ],
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "Location of the phone number (for country code)"
+ },
+ "search": {
+ "type": "object",
+ "description": "Phone numbers to search for",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid location",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}": {
+ "get": {
+ "operationId": "users-get-user",
+ "summary": "Get the details of a user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/UserDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "operationId": "users-edit-user",
+ "summary": "Update a value of the user's details",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "Key that will be updated"
+ },
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User value edited successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "users-delete-user",
+ "summary": "Delete a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user": {
+ "get": {
+ "operationId": "users-get-current-user",
+ "summary": "Get the details of the current user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Current user returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/UserDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user/fields": {
+ "get": {
+ "operationId": "users-get-editable-fields",
+ "summary": "Get a list of fields that are editable for the current user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Editable fields returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user/fields/{userId}": {
+ "get": {
+ "operationId": "users-get-editable-fields-for-user",
+ "summary": "Get a list of fields that are editable for a user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Editable fields for user returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/user/apps": {
+ "get": {
+ "operationId": "users-get-enabled-apps",
+ "summary": "Get a list of enabled apps for the current user",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Enabled apps returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "apps"
+ ],
+ "properties": {
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/{collectionName}": {
+ "put": {
+ "operationId": "users-edit-user-multi-value",
+ "summary": "Update multiple values of the user's details",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "Key that will be updated"
+ },
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "collectionName",
+ "in": "path",
+ "description": "Collection to update",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^(?!enable$|disable$)[a-zA-Z0-9_]*$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User values edited successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/wipe": {
+ "post": {
+ "operationId": "users-wipe-user-devices",
+ "summary": "Wipe all devices of a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Wiped all user devices successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/enable": {
+ "put": {
+ "operationId": "users-enable-user",
+ "summary": "Enable a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User enabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/disable": {
+ "put": {
+ "operationId": "users-disable-user",
+ "summary": "Disable a user",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User disabled successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/groups": {
+ "get": {
+ "operationId": "users-get-users-groups",
+ "summary": "Get a list of groups the user belongs to",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "operationId": "users-add-to-group",
+ "summary": "Add a user to a group",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "groupid": {
+ "type": "string",
+ "default": "",
+ "description": "ID of the group"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User added to group successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "users-remove-from-group",
+ "summary": "Remove a user from a group",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "groupid",
+ "in": "query",
+ "description": "ID of the group",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User removed from group successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/groups/details": {
+ "get": {
+ "operationId": "users-get-users-groups-details",
+ "summary": "Get a list of groups with details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GroupDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/subadmins/details": {
+ "get": {
+ "operationId": "users-get-user-sub-admin-groups-details",
+ "summary": "Get a list of the groups the user is a subadmin of, with details",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID of the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Users subadmin groups returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "groups"
+ ],
+ "properties": {
+ "groups": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GroupDetails"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/cloud/users/{userId}/welcome": {
+ "post": {
+ "operationId": "users-resend-welcome-message",
+ "summary": "Resend the welcome message",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "users"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "ID if the user",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Resent welcome message successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/apps/{app}/{key}": {
+ "post": {
+ "operationId": "app_config-set-value",
+ "summary": "Update the config value of an app",
+ "description": "This endpoint requires password confirmation",
+ "tags": [
+ "app_config"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "value"
+ ],
+ "properties": {
+ "value": {
+ "type": "string",
+ "description": "New value for the key"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "app",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "key",
+ "in": "path",
+ "description": "Key to update",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Value updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "App or key is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "data"
+ ],
+ "properties": {
+ "data": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/users/{appId}/{configKey}": {
+ "post": {
+ "operationId": "preferences-set-preference",
+ "summary": "Update a preference value of an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "configValue"
+ ],
+ "properties": {
+ "configValue": {
+ "type": "string",
+ "description": "New value"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "configKey",
+ "in": "path",
+ "description": "Key of the preference",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preference updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "preferences-delete-preference",
+ "summary": "Delete a preference for an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "configKey",
+ "in": "path",
+ "description": "Key to delete",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preference deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/ocs/v2.php/apps/provisioning_api/api/v1/config/users/{appId}": {
+ "post": {
+ "operationId": "preferences-set-multiple-preferences",
+ "summary": "Update multiple preference values of an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "configs"
+ ],
+ "properties": {
+ "configs": {
+ "type": "object",
+ "description": "Key-value pairs of the preferences",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preferences updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "preferences-delete-multiple-preference",
+ "summary": "Delete multiple preferences for an app",
+ "tags": [
+ "preferences"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "appId",
+ "in": "path",
+ "description": "ID of the app",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "configKeys[]",
+ "in": "query",
+ "description": "Keys to delete",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preferences deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Preference invalid",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/apps/provisioning_api/openapi.json.license b/apps/provisioning_api/openapi.json.license
new file mode 100644
index 00000000000..83559daa9dc
--- /dev/null
+++ b/apps/provisioning_api/openapi.json.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file
diff --git a/apps/provisioning_api/tests/CapabilitiesTest.php b/apps/provisioning_api/tests/CapabilitiesTest.php
new file mode 100644
index 00000000000..86d2bb8c4fa
--- /dev/null
+++ b/apps/provisioning_api/tests/CapabilitiesTest.php
@@ -0,0 +1,77 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Provisioning_API\Tests;
+
+use OCA\FederatedFileSharing\FederatedShareProvider;
+use OCA\Provisioning_API\Capabilities;
+use OCP\App\IAppManager;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+/**
+ * Capabilities test for provisioning API.
+ *
+ * Note: group DB needed because of usage of overwriteService()
+ *
+ * @package OCA\Provisioning_API\Tests
+ * @group DB
+ */
+class CapabilitiesTest extends TestCase {
+
+ protected IAppManager&MockObject $appManager;
+ protected Capabilities $capabilities;
+
+ public function setUp(): void {
+ parent::setUp();
+ $this->appManager = $this->createMock(IAppManager::class);
+ $this->capabilities = new Capabilities($this->appManager);
+
+ $this->appManager->expects($this->once())
+ ->method('getAppVersion')
+ ->with('provisioning_api')
+ ->willReturn('1.12');
+ }
+
+ public static function getCapabilitiesProvider(): array {
+ return [
+ [true, false, false, true, false],
+ [true, true, false, true, false],
+ [true, true, true, true, true],
+ [false, false, false, false, false],
+ [false, true, false, false, false],
+ [false, true, true, false, true],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('getCapabilitiesProvider')]
+ public function testGetCapabilities(bool $federationAppEnabled, bool $federatedFileSharingAppEnabled, bool $lookupServerEnabled, bool $expectedFederatedScopeEnabled, bool $expectedPublishedScopeEnabled): void {
+ $this->appManager->expects($this->any())
+ ->method('isEnabledForUser')
+ ->willReturnMap([
+ ['federation', null, $federationAppEnabled],
+ ['federatedfilesharing', null, $federatedFileSharingAppEnabled],
+ ]);
+
+ $federatedShareProvider = $this->createMock(FederatedShareProvider::class);
+ $this->overwriteService(FederatedShareProvider::class, $federatedShareProvider);
+
+ $federatedShareProvider->expects($this->any())
+ ->method('isLookupServerUploadEnabled')
+ ->willReturn($lookupServerEnabled);
+
+ $expected = [
+ 'provisioning_api' => [
+ 'version' => '1.12',
+ 'AccountPropertyScopesVersion' => 2,
+ 'AccountPropertyScopesFederatedEnabled' => $expectedFederatedScopeEnabled,
+ 'AccountPropertyScopesPublishedEnabled' => $expectedPublishedScopeEnabled,
+ ],
+ ];
+ $this->assertSame($expected, $this->capabilities->getCapabilities());
+ }
+}
diff --git a/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php b/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php
index 7f24ef5bcb3..1b09838cbc3 100644
--- a/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php
+++ b/apps/provisioning_api/tests/Controller/AppConfigControllerTest.php
@@ -1,36 +1,30 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2016 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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\Provisioning_API\Tests\Controller;
-
+use OC\AppConfig;
use OCA\Provisioning_API\Controller\AppConfigController;
+use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
+use OCP\Exceptions\AppConfigUnknownKeyException;
use OCP\IAppConfig;
-use OCP\IConfig;
+use OCP\IGroupManager;
+use OCP\IL10N;
use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Server;
+use OCP\Settings\IManager;
+use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
+use function json_decode;
+use function json_encode;
/**
* Class AppConfigControllerTest
@@ -38,23 +32,27 @@ use Test\TestCase;
* @package OCA\Provisioning_API\Tests
*/
class AppConfigControllerTest extends TestCase {
-
- /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
- private $config;
- /** @var IAppConfig|\PHPUnit_Framework_MockObject_MockObject */
- private $appConfig;
-
- protected function setUp() {
+ private IAppConfig&MockObject $appConfig;
+ private IUserSession&MockObject $userSession;
+ private IL10N&MockObject $l10n;
+ private IManager&MockObject $settingManager;
+ private IGroupManager&MockObject $groupManager;
+ private IAppManager $appManager;
+
+ protected function setUp(): void {
parent::setUp();
- $this->config = $this->createMock(IConfig::class);
- $this->appConfig = $this->createMock(IAppConfig::class);
-
+ $this->appConfig = $this->createMock(AppConfig::class);
+ $this->userSession = $this->createMock(IUserSession::class);
+ $this->l10n = $this->createMock(IL10N::class);
+ $this->settingManager = $this->createMock(IManager::class);
+ $this->groupManager = $this->createMock(IGroupManager::class);
+ $this->appManager = Server::get(IAppManager::class);
}
/**
* @param string[] $methods
- * @return AppConfigController|\PHPUnit_Framework_MockObject_MockObject
+ * @return AppConfigController|MockObject
*/
protected function getInstance(array $methods = []) {
$request = $this->createMock(IRequest::class);
@@ -63,23 +61,31 @@ class AppConfigControllerTest extends TestCase {
return new AppConfigController(
'provisioning_api',
$request,
- $this->config,
- $this->appConfig
+ $this->appConfig,
+ $this->userSession,
+ $this->l10n,
+ $this->groupManager,
+ $this->settingManager,
+ $this->appManager,
);
} else {
return $this->getMockBuilder(AppConfigController::class)
->setConstructorArgs([
'provisioning_api',
$request,
- $this->config,
$this->appConfig,
+ $this->userSession,
+ $this->l10n,
+ $this->groupManager,
+ $this->settingManager,
+ $this->appManager,
])
- ->setMethods($methods)
+ ->onlyMethods($methods)
->getMock();
}
}
- public function testGetApps() {
+ public function testGetApps(): void {
$this->appConfig->expects($this->once())
->method('getApps')
->willReturn(['apps']);
@@ -90,22 +96,15 @@ class AppConfigControllerTest extends TestCase {
$this->assertEquals(['data' => ['apps']], $result->getData());
}
- public function dataGetKeys() {
+ public static function dataGetKeys(): array {
return [
['app1 ', null, new \InvalidArgumentException('error'), Http::STATUS_FORBIDDEN],
['app2', ['keys'], null, Http::STATUS_OK],
];
}
- /**
- * @dataProvider dataGetKeys
- * @param string $app
- * @param array|null $keys
- * @param \Exception|null $throws
- * @param int $status
- */
- public function testGetKeys($app, $keys, $throws, $status) {
-
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetKeys')]
+ public function testGetKeys(string $app, ?array $keys, ?\Throwable $throws, int $status): void {
$api = $this->getInstance(['verifyAppId']);
if ($throws instanceof \Exception) {
$api->expects($this->once())
@@ -113,15 +112,15 @@ class AppConfigControllerTest extends TestCase {
->with($app)
->willThrowException($throws);
- $this->config->expects($this->never())
- ->method('getAppKeys');
+ $this->appConfig->expects($this->never())
+ ->method('getKeys');
} else {
$api->expects($this->once())
->method('verifyAppId')
->with($app);
- $this->config->expects($this->once())
- ->method('getAppKeys')
+ $this->appConfig->expects($this->once())
+ ->method('getKeys')
->with($app)
->willReturn($keys);
}
@@ -136,40 +135,28 @@ class AppConfigControllerTest extends TestCase {
}
}
- public function dataGetValue() {
+ public static function dataGetValue(): array {
return [
- ['app1 ', null, null, null, new \InvalidArgumentException('error'), Http::STATUS_FORBIDDEN],
+ ['app1', 'key', 'default', null, new \InvalidArgumentException('error'), Http::STATUS_FORBIDDEN],
['app2', 'key', 'default', 'return', null, Http::STATUS_OK],
];
}
- /**
- * @dataProvider dataGetValue
- * @param string $app
- * @param string|null $key
- * @param string|null $default
- * @param string|null $return
- * @param \Exception|null $throws
- * @param int $status
- */
- public function testGetValue($app, $key, $default, $return, $throws, $status) {
-
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetValue')]
+ public function testGetValue(string $app, string $key, string $default, ?string $return, ?\Throwable $throws, int $status): void {
$api = $this->getInstance(['verifyAppId']);
if ($throws instanceof \Exception) {
$api->expects($this->once())
->method('verifyAppId')
->with($app)
->willThrowException($throws);
-
- $this->config->expects($this->never())
- ->method('getAppValue');
} else {
$api->expects($this->once())
->method('verifyAppId')
->with($app);
- $this->config->expects($this->once())
- ->method('getAppValue')
+ $this->appConfig->expects($this->once())
+ ->method('getValueMixed')
->with($app, $key, $default)
->willReturn($return);
}
@@ -184,25 +171,35 @@ class AppConfigControllerTest extends TestCase {
}
}
- public function dataSetValue() {
+ public static function dataSetValue(): array {
return [
- ['app1 ', null, null, new \InvalidArgumentException('error1'), null, Http::STATUS_FORBIDDEN],
- ['app2', 'key', null, null, new \InvalidArgumentException('error2'), Http::STATUS_FORBIDDEN],
+ ['app1', 'key', 'default', new \InvalidArgumentException('error1'), null, Http::STATUS_FORBIDDEN],
+ ['app2', 'key', 'default', null, new \InvalidArgumentException('error2'), Http::STATUS_FORBIDDEN],
['app2', 'key', 'default', null, null, Http::STATUS_OK],
+ ['app2', 'key', '1', null, null, Http::STATUS_OK, IAppConfig::VALUE_BOOL],
+ ['app2', 'key', '42', null, null, Http::STATUS_OK, IAppConfig::VALUE_INT],
+ ['app2', 'key', '4.2', null, null, Http::STATUS_OK, IAppConfig::VALUE_FLOAT],
+ ['app2', 'key', '42', null, null, Http::STATUS_OK, IAppConfig::VALUE_STRING],
+ ['app2', 'key', 'secret', null, null, Http::STATUS_OK, IAppConfig::VALUE_STRING | IAppConfig::VALUE_SENSITIVE],
+ ['app2', 'key', json_encode([4, 2]), null, null, Http::STATUS_OK, IAppConfig::VALUE_ARRAY],
+ ['app2', 'key', json_encode([4, 2]), null, null, Http::STATUS_OK, new AppConfigUnknownKeyException()],
];
}
- /**
- * @dataProvider dataSetValue
- * @param string $app
- * @param string|null $key
- * @param string|null $value
- * @param \Exception|null $appThrows
- * @param \Exception|null $keyThrows
- * @param int $status
- */
- public function testSetValue($app, $key, $value, $appThrows, $keyThrows, $status) {
-
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSetValue')]
+ public function testSetValue(string $app, string $key, string $value, ?\Throwable $appThrows, ?\Throwable $keyThrows, int $status, int|\Throwable $type = IAppConfig::VALUE_MIXED): void {
+ $adminUser = $this->createMock(IUser::class);
+ $adminUser->expects($this->once())
+ ->method('getUid')
+ ->willReturn('admin');
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->willReturn($adminUser);
+ $this->groupManager->expects($this->once())
+ ->method('isAdmin')
+ ->with('admin')
+ ->willReturn(true);
$api = $this->getInstance(['verifyAppId', 'verifyConfigKey']);
if ($appThrows instanceof \Exception) {
$api->expects($this->once())
@@ -212,9 +209,9 @@ class AppConfigControllerTest extends TestCase {
$api->expects($this->never())
->method('verifyConfigKey');
- $this->config->expects($this->never())
- ->method('setAppValue');
- } else if ($keyThrows instanceof \Exception) {
+ $this->appConfig->expects($this->never())
+ ->method('setValueMixed');
+ } elseif ($keyThrows instanceof \Exception) {
$api->expects($this->once())
->method('verifyAppId')
->with($app);
@@ -223,8 +220,8 @@ class AppConfigControllerTest extends TestCase {
->with($app, $key)
->willThrowException($keyThrows);
- $this->config->expects($this->never())
- ->method('setAppValue');
+ $this->appConfig->expects($this->never())
+ ->method('setValueMixed');
} else {
$api->expects($this->once())
->method('verifyAppId')
@@ -233,9 +230,38 @@ class AppConfigControllerTest extends TestCase {
->method('verifyConfigKey')
->with($app, $key);
- $this->config->expects($this->once())
- ->method('setAppValue')
- ->with($app, $key, $value);
+ if ($type instanceof \Throwable) {
+ $this->appConfig->expects($this->once())
+ ->method('getDetails')
+ ->with($app, $key)
+ ->willThrowException($type);
+ } else {
+ $this->appConfig->expects($this->once())
+ ->method('getDetails')
+ ->with($app, $key)
+ ->willReturn([
+ 'app' => $app,
+ 'key' => $key,
+ 'value' => '', // 🤷
+ 'type' => $type,
+ 'lazy' => false,
+ 'typeString' => (string)$type, // this is not accurate, but acceptable
+ 'sensitive' => ($type & IAppConfig::VALUE_SENSITIVE) !== 0,
+ ]);
+ }
+
+ $configValueSetter = match ($type) {
+ IAppConfig::VALUE_BOOL => 'setValueBool',
+ IAppConfig::VALUE_FLOAT => 'setValueFloat',
+ IAppConfig::VALUE_INT => 'setValueInt',
+ IAppConfig::VALUE_STRING => 'setValueString',
+ IAppConfig::VALUE_ARRAY => 'setValueArray',
+ default => 'setValueMixed',
+ };
+
+ $this->appConfig->expects($this->once())
+ ->method($configValueSetter)
+ ->with($app, $key, $configValueSetter === 'setValueArray' ? json_decode($value, true) : $value);
}
$result = $api->setValue($app, $key, $value);
@@ -243,31 +269,23 @@ class AppConfigControllerTest extends TestCase {
$this->assertSame($status, $result->getStatus());
if ($appThrows instanceof \Exception) {
$this->assertEquals(['data' => ['message' => $appThrows->getMessage()]], $result->getData());
- } else if ($keyThrows instanceof \Exception) {
+ } elseif ($keyThrows instanceof \Exception) {
$this->assertEquals(['data' => ['message' => $keyThrows->getMessage()]], $result->getData());
} else {
$this->assertEquals([], $result->getData());
}
}
- public function dataDeleteValue() {
+ public static function dataDeleteValue(): array {
return [
- ['app1 ', null, new \InvalidArgumentException('error1'), null, Http::STATUS_FORBIDDEN],
+ ['app1', 'key', new \InvalidArgumentException('error1'), null, Http::STATUS_FORBIDDEN],
['app2', 'key', null, new \InvalidArgumentException('error2'), Http::STATUS_FORBIDDEN],
['app2', 'key', null, null, Http::STATUS_OK],
];
}
- /**
- * @dataProvider dataDeleteValue
- * @param string $app
- * @param string|null $key
- * @param \Exception|null $appThrows
- * @param \Exception|null $keyThrows
- * @param int $status
- */
- public function testDeleteValue($app, $key, $appThrows, $keyThrows, $status) {
-
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteValue')]
+ public function testDeleteValue(string $app, string $key, ?\Throwable $appThrows, ?\Throwable $keyThrows, int $status): void {
$api = $this->getInstance(['verifyAppId', 'verifyConfigKey']);
if ($appThrows instanceof \Exception) {
$api->expects($this->once())
@@ -277,9 +295,9 @@ class AppConfigControllerTest extends TestCase {
$api->expects($this->never())
->method('verifyConfigKey');
- $this->config->expects($this->never())
- ->method('deleteAppValue');
- } else if ($keyThrows instanceof \Exception) {
+ $this->appConfig->expects($this->never())
+ ->method('deleteKey');
+ } elseif ($keyThrows instanceof \Exception) {
$api->expects($this->once())
->method('verifyAppId')
->with($app);
@@ -288,8 +306,8 @@ class AppConfigControllerTest extends TestCase {
->with($app, $key)
->willThrowException($keyThrows);
- $this->config->expects($this->never())
- ->method('deleteAppValue');
+ $this->appConfig->expects($this->never())
+ ->method('deleteKey');
} else {
$api->expects($this->once())
->method('verifyAppId')
@@ -298,8 +316,8 @@ class AppConfigControllerTest extends TestCase {
->method('verifyConfigKey')
->with($app, $key);
- $this->config->expects($this->once())
- ->method('deleteAppValue')
+ $this->appConfig->expects($this->once())
+ ->method('deleteKey')
->with($app, $key);
}
@@ -308,20 +326,20 @@ class AppConfigControllerTest extends TestCase {
$this->assertSame($status, $result->getStatus());
if ($appThrows instanceof \Exception) {
$this->assertEquals(['data' => ['message' => $appThrows->getMessage()]], $result->getData());
- } else if ($keyThrows instanceof \Exception) {
+ } elseif ($keyThrows instanceof \Exception) {
$this->assertEquals(['data' => ['message' => $keyThrows->getMessage()]], $result->getData());
} else {
$this->assertEquals([], $result->getData());
}
}
- public function testVerifyAppId() {
+ public function testVerifyAppId(): void {
$api = $this->getInstance();
$this->invokePrivate($api, 'verifyAppId', ['activity']);
- $this->assertTrue(true);
+ $this->addToAssertionCount(1);
}
- public function dataVerifyAppIdThrows() {
+ public static function dataVerifyAppIdThrows(): array {
return [
['activity..'],
['activity/'],
@@ -330,55 +348,49 @@ class AppConfigControllerTest extends TestCase {
];
}
- /**
- * @dataProvider dataVerifyAppIdThrows
- * @expectedException \InvalidArgumentException
- * @param string $app
- */
- public function testVerifyAppIdThrows($app) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataVerifyAppIdThrows')]
+ public function testVerifyAppIdThrows(string $app): void {
+ $this->expectException(\InvalidArgumentException::class);
+
$api = $this->getInstance();
$this->invokePrivate($api, 'verifyAppId', [$app]);
}
- public function dataVerifyConfigKey() {
+ public static function dataVerifyConfigKey(): array {
return [
- ['activity', 'abc'],
- ['dav', 'public_route'],
- ['files', 'remote_route'],
+ ['activity', 'abc', ''],
+ ['dav', 'public_route', ''],
+ ['files', 'remote_route', ''],
+ ['core', 'encryption_enabled', 'yes'],
];
}
- /**
- * @dataProvider dataVerifyConfigKey
- * @param string $app
- * @param string $key
- */
- public function testVerifyConfigKey($app, $key) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataVerifyConfigKey')]
+ public function testVerifyConfigKey(string $app, string $key, string $value): void {
$api = $this->getInstance();
- $this->invokePrivate($api, 'verifyConfigKey', [$app, $key]);
- $this->assertTrue(true);
+ $this->invokePrivate($api, 'verifyConfigKey', [$app, $key, $value]);
+ $this->addToAssertionCount(1);
}
- public function dataVerifyConfigKeyThrows() {
+ public static function dataVerifyConfigKeyThrows(): array {
return [
- ['activity', 'installed_version'],
- ['calendar', 'enabled'],
- ['contacts', 'types'],
- ['core', 'public_files'],
- ['core', 'public_dav'],
- ['core', 'remote_files'],
- ['core', 'remote_dav'],
+ ['activity', 'installed_version', ''],
+ ['calendar', 'enabled', ''],
+ ['contacts', 'types', ''],
+ ['core', 'encryption_enabled', 'no'],
+ ['core', 'encryption_enabled', ''],
+ ['core', 'public_files', ''],
+ ['core', 'public_dav', ''],
+ ['core', 'remote_files', ''],
+ ['core', 'remote_dav', ''],
];
}
- /**
- * @dataProvider dataVerifyConfigKeyThrows
- * @expectedException \InvalidArgumentException
- * @param string $app
- * @param string $key
- */
- public function testVerifyConfigKeyThrows($app, $key) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataVerifyConfigKeyThrows')]
+ public function testVerifyConfigKeyThrows(string $app, string $key, string $value): void {
+ $this->expectException(\InvalidArgumentException::class);
+
$api = $this->getInstance();
- $this->invokePrivate($api, 'verifyConfigKey', [$app, $key]);
+ $this->invokePrivate($api, 'verifyConfigKey', [$app, $key, $value]);
}
}
diff --git a/apps/provisioning_api/tests/Controller/AppsControllerTest.php b/apps/provisioning_api/tests/Controller/AppsControllerTest.php
index 7bd20e4233f..f95daeae7d3 100644
--- a/apps/provisioning_api/tests/Controller/AppsControllerTest.php
+++ b/apps/provisioning_api/tests/Controller/AppsControllerTest.php
@@ -1,37 +1,23 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Provisioning_API\Tests\Controller;
-
+use OC\Installer;
use OCA\Provisioning_API\Controller\AppsController;
+use OCA\Provisioning_API\Tests\TestCase;
use OCP\App\IAppManager;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\IAppConfig;
+use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUserSession;
+use OCP\Server;
+use PHPUnit\Framework\MockObject\MockObject;
/**
* Class AppsTest
@@ -40,47 +26,52 @@ use OCP\IUserSession;
*
* @package OCA\Provisioning_API\Tests
*/
-class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
- /** @var IAppManager */
- private $appManager;
- /** @var AppsController */
- private $api;
- /** @var IUserSession */
- private $userSession;
-
- protected function setUp() {
+class AppsControllerTest extends TestCase {
+ private IAppManager $appManager;
+ private IAppConfig&MockObject $appConfig;
+ private Installer&MockObject $installer;
+ private AppsController $api;
+ private IUserSession $userSession;
+
+ protected function setUp(): void {
parent::setUp();
- $this->appManager = \OC::$server->getAppManager();
- $this->groupManager = \OC::$server->getGroupManager();
- $this->userSession = \OC::$server->getUserSession();
+ $this->appManager = Server::get(IAppManager::class);
+ $this->groupManager = Server::get(IGroupManager::class);
+ $this->userSession = Server::get(IUserSession::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
+ $this->installer = $this->createMock(Installer::class);
- $request = $this->getMockBuilder(IRequest::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $request = $this->createMock(IRequest::class);
$this->api = new AppsController(
'provisioning_api',
$request,
- $this->appManager
+ $this->appManager,
+ $this->installer,
+ $this->appConfig,
);
}
- public function testGetAppInfo() {
+ protected function tearDown(): void {
+ $this->userSession->setUser(null);
+ }
+
+ public function testGetAppInfo(): void {
$result = $this->api->getAppInfo('provisioning_api');
- $expected = \OC_App::getAppInfo('provisioning_api');
+ $expected = $this->appManager->getAppInfo('provisioning_api');
$this->assertEquals($expected, $result->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 998
- */
- public function testGetAppInfoOnBadAppID() {
+
+ public function testGetAppInfoOnBadAppID(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$this->api->getAppInfo('not_provisioning_api');
}
- public function testGetApps() {
+ public function testGetApps(): void {
$user = $this->generateUsers();
$this->groupManager->get('admin')->addUser($user);
$this->userSession->setUser($user);
@@ -91,29 +82,29 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
$this->assertEquals(count((new \OC_App())->listAllApps()), count($data['apps']));
}
- public function testGetAppsEnabled() {
+ public function testGetAppsEnabled(): void {
$result = $this->api->getApps('enabled');
$data = $result->getData();
$this->assertEquals(count(\OC_App::getEnabledApps()), count($data['apps']));
}
- public function testGetAppsDisabled() {
+ public function testGetAppsDisabled(): void {
$result = $this->api->getApps('disabled');
$data = $result->getData();
$apps = (new \OC_App)->listAllApps();
- $list = array();
- foreach($apps as $app) {
+ $list = [];
+ foreach ($apps as $app) {
$list[] = $app['id'];
}
$disabled = array_diff($list, \OC_App::getEnabledApps());
$this->assertEquals(count($disabled), count($data['apps']));
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testGetAppsInvalidFilter() {
+
+ public function testGetAppsInvalidFilter(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$this->api->getApps('foo');
}
}
diff --git a/apps/provisioning_api/tests/Controller/GroupsControllerTest.php b/apps/provisioning_api/tests/Controller/GroupsControllerTest.php
index cd3dae79336..85e5d733b1f 100644
--- a/apps/provisioning_api/tests/Controller/GroupsControllerTest.php
+++ b/apps/provisioning_api/tests/Controller/GroupsControllerTest.php
@@ -1,102 +1,118 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Provisioning_API\Tests\Controller;
+use OC\Group\Manager;
+use OC\User\NoUserException;
use OCA\Provisioning_API\Controller\GroupsController;
-use OCP\IGroupManager;
-use OCP\ILogger;
+use OCP\Accounts\IAccountManager;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\Files\IRootFolder;
+use OCP\Group\ISubAdmin;
+use OCP\IConfig;
+use OCP\IGroup;
use OCP\IRequest;
use OCP\IUser;
+use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\L10N\IFactory;
+use OCP\UserInterface;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
class GroupsControllerTest extends \Test\TestCase {
- /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
- protected $groupManager;
- /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
- protected $userSession;
- /** @var \OC\SubAdmin|\PHPUnit_Framework_MockObject_MockObject */
- protected $subAdminManager;
+ protected IRequest&MockObject $request;
+ protected IUserManager&MockObject $userManager;
+ protected IConfig&MockObject $config;
+ protected Manager&MockObject $groupManager;
+ protected IUserSession&MockObject $userSession;
+ protected IAccountManager&MockObject $accountManager;
+ protected ISubAdmin&MockObject $subAdminManager;
+ protected IFactory&MockObject $l10nFactory;
+ protected LoggerInterface&MockObject $logger;
+ protected GroupsController&MockObject $api;
- /** @var GroupsController */
- protected $api;
+ private IRootFolder $rootFolder;
- protected function setUp() {
+
+ protected function setUp(): void {
parent::setUp();
- $this->subAdminManager = $this->getMockBuilder('OC\SubAdmin')
- ->disableOriginalConstructor()
- ->getMock();
+ $this->request = $this->createMock(IRequest::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->config = $this->createMock(IConfig::class);
+ $this->groupManager = $this->createMock(Manager::class);
+ $this->userSession = $this->createMock(IUserSession::class);
+ $this->accountManager = $this->createMock(IAccountManager::class);
+ $this->subAdminManager = $this->createMock(ISubAdmin::class);
+ $this->l10nFactory = $this->createMock(IFactory::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->rootFolder = $this->createMock(IRootFolder::class);
- $this->groupManager = $this->getMockBuilder('OC\Group\Manager')
- ->disableOriginalConstructor()
- ->getMock();
$this->groupManager
->method('getSubAdmin')
->willReturn($this->subAdminManager);
- $this->userSession = $this->getMockBuilder(IUserSession::class)
- ->disableOriginalConstructor()
- ->getMock();
- $request = $this->getMockBuilder(IRequest::class)
- ->disableOriginalConstructor()
+ $this->api = $this->getMockBuilder(GroupsController::class)
+ ->setConstructorArgs([
+ 'provisioning_api',
+ $this->request,
+ $this->userManager,
+ $this->config,
+ $this->groupManager,
+ $this->userSession,
+ $this->accountManager,
+ $this->subAdminManager,
+ $this->l10nFactory,
+ $this->rootFolder,
+ $this->logger
+ ])
+ ->onlyMethods(['fillStorageInfo'])
->getMock();
-
- $logger = $this->createMock(ILogger::class);
-
- $this->api = new GroupsController(
- 'provisioning_api',
- $request,
- $this->groupManager,
- $this->userSession,
- $logger
- );
}
- /**
- * @param string $gid
- * @return \OCP\IGroup|\PHPUnit_Framework_MockObject_MockObject
- */
- private function createGroup($gid) {
- $group = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
+ private function createGroup(string $gid): IGroup&MockObject {
+ $group = $this->createMock(IGroup::class);
$group
->method('getGID')
->willReturn($gid);
+ $group
+ ->method('getDisplayName')
+ ->willReturn($gid . '-name');
+ $group
+ ->method('count')
+ ->willReturn(123);
+ $group
+ ->method('countDisabled')
+ ->willReturn(11);
+ $group
+ ->method('canAddUser')
+ ->willReturn(true);
+ $group
+ ->method('canRemoveUser')
+ ->willReturn(true);
+
return $group;
}
/**
* @param string $uid
- * @return \OCP\IUser|\PHPUnit_Framework_MockObject_MockObject
+ * @return IUser&MockObject
*/
private function createUser($uid) {
$user = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$user
->method('getUID')
->willReturn($uid);
+ $backendMock = $this->createMock(UserInterface::class);
+ $user
+ ->method('getBackend')
+ ->willReturn($backendMock);
return $user;
}
@@ -127,32 +143,48 @@ class GroupsControllerTest extends \Test\TestCase {
$this->subAdminManager
->method('isSubAdminOfGroup')
- ->will($this->returnCallback(function($_user, $_group) use ($user, $group) {
+ ->willReturnCallback(function ($_user, $_group) use ($user, $group) {
if ($_user === $user && $_group === $group) {
return true;
}
return false;
- }));
+ });
}
- public function dataGetGroups() {
+ public static function dataGetGroups(): array {
return [
- [null, null, null],
- ['foo', null, null],
- [null, 1, null],
- [null, null, 2],
+ [null, 0, 0],
+ ['foo', 0, 0],
+ [null, 1, 0],
+ [null, 0, 2],
['foo', 1, 2],
];
}
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetGroups')]
+ public function testGetGroups(?string $search, int $limit, int $offset): void {
+ $groups = [$this->createGroup('group1'), $this->createGroup('group2')];
+
+ $search = $search === null ? '' : $search;
+
+ $this->groupManager
+ ->expects($this->once())
+ ->method('search')
+ ->with($search, $limit, $offset)
+ ->willReturn($groups);
+
+ $result = $this->api->getGroups($search, $limit, $offset);
+ $this->assertEquals(['groups' => ['group1', 'group2']], $result->getData());
+ }
+
/**
- * @dataProvider dataGetGroups
*
* @param string|null $search
* @param int|null $limit
* @param int|null $offset
*/
- public function testGetGroups($search, $limit, $offset) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetGroups')]
+ public function testGetGroupsDetails($search, $limit, $offset): void {
$groups = [$this->createGroup('group1'), $this->createGroup('group2')];
$search = $search === null ? '' : $search;
@@ -163,11 +195,28 @@ class GroupsControllerTest extends \Test\TestCase {
->with($search, $limit, $offset)
->willReturn($groups);
- $result = $this->api->getGroups($search, $limit, $offset);
- $this->assertEquals(['groups' => ['group1', 'group2']], $result->getData());
+ $result = $this->api->getGroupsDetails($search, $limit, $offset);
+ $this->assertEquals(['groups' => [
+ [
+ 'id' => 'group1',
+ 'displayname' => 'group1-name',
+ 'usercount' => 123,
+ 'disabled' => 11,
+ 'canAdd' => true,
+ 'canRemove' => true
+ ],
+ [
+ 'id' => 'group2',
+ 'displayname' => 'group2-name',
+ 'usercount' => 123,
+ 'disabled' => 11,
+ 'canAdd' => true,
+ 'canRemove' => true
+ ]
+ ]], $result->getData());
}
- public function testGetGroupAsSubadmin() {
+ public function testGetGroupAsSubadmin(): void {
$group = $this->createGroup('group');
$this->asSubAdminOfGroup($group);
@@ -191,11 +240,11 @@ class GroupsControllerTest extends \Test\TestCase {
$this->assertEquals(['users' => ['user1', 'user2']], $result->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testGetGroupAsIrrelevantSubadmin() {
+
+ public function testGetGroupAsIrrelevantSubadmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(403);
+
$group = $this->createGroup('group');
$otherGroup = $this->createGroup('otherGroup');
$this->asSubAdminOfGroup($otherGroup);
@@ -212,7 +261,7 @@ class GroupsControllerTest extends \Test\TestCase {
$this->api->getGroup('group');
}
- public function testGetGroupAsAdmin() {
+ public function testGetGroupAsAdmin(): void {
$group = $this->createGroup('group');
$this->asAdmin();
@@ -236,27 +285,27 @@ class GroupsControllerTest extends \Test\TestCase {
$this->assertEquals(['users' => ['user1', 'user2']], $result->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 998
- * @expectedExceptionMessage The requested group could not be found
- */
- public function testGetGroupNonExisting() {
+
+ public function testGetGroupNonExisting(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('The requested group could not be found');
+ $this->expectExceptionCode(404);
+
$this->asUser();
$this->api->getGroup($this->getUniqueID());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage Group does not exist
- */
- public function testGetSubAdminsOfGroupsNotExists() {
+
+ public function testGetSubAdminsOfGroupsNotExists(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Group does not exist');
+ $this->expectExceptionCode(101);
+
$this->api->getSubAdminsOfGroup('NonExistingGroup');
}
- public function testGetSubAdminsOfGroup() {
+ public function testGetSubAdminsOfGroup(): void {
$group = $this->createGroup('GroupWithSubAdmins');
$this->groupManager
->method('get')
@@ -276,7 +325,7 @@ class GroupsControllerTest extends \Test\TestCase {
$this->assertEquals(['SubAdmin1', 'SubAdmin2'], $result->getData());
}
- public function testGetSubAdminsOfGroupEmptyList() {
+ public function testGetSubAdminsOfGroupEmptyList(): void {
$group = $this->createGroup('GroupWithOutSubAdmins');
$this->groupManager
->method('get')
@@ -294,20 +343,20 @@ class GroupsControllerTest extends \Test\TestCase {
$this->assertEquals([], $result->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage Invalid group name
- */
- public function testAddGroupEmptyGroup() {
+
+ public function testAddGroupEmptyGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Invalid group name');
+ $this->expectExceptionCode(101);
+
$this->api->addGroup('');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- */
- public function testAddGroupExistingGroup() {
+
+ public function testAddGroupExistingGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(102);
+
$this->groupManager
->method('groupExists')
->with('ExistingGroup')
@@ -316,47 +365,51 @@ class GroupsControllerTest extends \Test\TestCase {
$this->api->addGroup('ExistingGroup');
}
- public function testAddGroup() {
+ public function testAddGroup(): void {
$this->groupManager
->method('groupExists')
->with('NewGroup')
->willReturn(false);
+ $group = $this->createGroup('NewGroup');
$this->groupManager
->expects($this->once())
->method('createGroup')
- ->with('NewGroup');
+ ->with('NewGroup')
+ ->willReturn($group);
$this->api->addGroup('NewGroup');
}
- public function testAddGroupWithSpecialChar() {
+ public function testAddGroupWithSpecialChar(): void {
$this->groupManager
->method('groupExists')
->with('Iñtërnâtiônàlizætiøn')
->willReturn(false);
+ $group = $this->createGroup('Iñtërnâtiônàlizætiøn');
$this->groupManager
->expects($this->once())
->method('createGroup')
- ->with('Iñtërnâtiônàlizætiøn');
+ ->with('Iñtërnâtiônàlizætiøn')
+ ->willReturn($group);
$this->api->addGroup('Iñtërnâtiônàlizætiøn');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testDeleteGroupNonExisting() {
+
+ public function testDeleteGroupNonExisting(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$this->api->deleteGroup('NonExistingGroup');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- */
- public function testDeleteAdminGroup() {
+
+ public function testDeleteAdminGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(102);
+
$this->groupManager
->method('groupExists')
->with('admin')
@@ -365,7 +418,7 @@ class GroupsControllerTest extends \Test\TestCase {
$this->api->deleteGroup('admin');
}
- public function testDeleteGroup() {
+ public function testDeleteGroup(): void {
$this->groupManager
->method('groupExists')
->with('ExistingGroup')
@@ -383,4 +436,113 @@ class GroupsControllerTest extends \Test\TestCase {
$this->api->deleteGroup('ExistingGroup');
}
+
+ public function testDeleteGroupEncoding(): void {
+ $this->groupManager
+ ->method('groupExists')
+ ->with('ExistingGroup A/B')
+ ->willReturn('true');
+
+ $group = $this->createGroup('ExistingGroup');
+ $this->groupManager
+ ->method('get')
+ ->with('ExistingGroup A/B')
+ ->willReturn($group);
+ $group
+ ->expects($this->once())
+ ->method('delete')
+ ->willReturn(true);
+
+ $this->api->deleteGroup(urlencode('ExistingGroup A/B'));
+ }
+
+ public function testGetGroupUsersDetails(): void {
+ $gid = 'ncg1';
+
+ $this->asAdmin();
+
+ $users = [
+ 'ncu1' => $this->createUser('ncu1'), # regular
+ 'ncu2' => $this->createUser('ncu2'), # the zombie
+ ];
+ $users['ncu2']->expects($this->atLeastOnce())
+ ->method('getHome')
+ ->willThrowException(new NoUserException());
+
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->willReturnCallback(function (string $uid) use ($users) {
+ return $users[$uid] ?? null;
+ });
+
+ $group = $this->createGroup($gid);
+ $group->expects($this->once())
+ ->method('searchUsers')
+ ->with('', null, 0)
+ ->willReturn(array_values($users));
+
+ $this->groupManager
+ ->method('get')
+ ->with($gid)
+ ->willReturn($group);
+ $this->groupManager->expects($this->any())
+ ->method('getUserGroups')
+ ->willReturn([$group]);
+
+ /** @var MockObject */
+ $this->subAdminManager->expects($this->any())
+ ->method('isSubAdminOfGroup')
+ ->willReturn(false);
+ $this->subAdminManager->expects($this->any())
+ ->method('getSubAdminsGroups')
+ ->willReturn([]);
+
+
+ $this->api->getGroupUsersDetails($gid);
+ }
+
+ public function testGetGroupUsersDetailsEncoded(): void {
+ $gid = 'Department A/B C/D';
+
+ $this->asAdmin();
+
+ $users = [
+ 'ncu1' => $this->createUser('ncu1'), # regular
+ 'ncu2' => $this->createUser('ncu2'), # the zombie
+ ];
+ $users['ncu2']->expects($this->atLeastOnce())
+ ->method('getHome')
+ ->willThrowException(new NoUserException());
+
+ $this->userManager->expects($this->any())
+ ->method('get')
+ ->willReturnCallback(function (string $uid) use ($users) {
+ return $users[$uid] ?? null;
+ });
+
+ $group = $this->createGroup($gid);
+ $group->expects($this->once())
+ ->method('searchUsers')
+ ->with('', null, 0)
+ ->willReturn(array_values($users));
+
+ $this->groupManager
+ ->method('get')
+ ->with($gid)
+ ->willReturn($group);
+ $this->groupManager->expects($this->any())
+ ->method('getUserGroups')
+ ->willReturn([$group]);
+
+ /** @var MockObject */
+ $this->subAdminManager->expects($this->any())
+ ->method('isSubAdminOfGroup')
+ ->willReturn(false);
+ $this->subAdminManager->expects($this->any())
+ ->method('getSubAdminsGroups')
+ ->willReturn([]);
+
+
+ $this->api->getGroupUsersDetails(urlencode($gid));
+ }
}
diff --git a/apps/provisioning_api/tests/Controller/UsersControllerTest.php b/apps/provisioning_api/tests/Controller/UsersControllerTest.php
index ef47583e9df..0c0a0ae3d74 100644
--- a/apps/provisioning_api/tests/Controller/UsersControllerTest.php
+++ b/apps/provisioning_api/tests/Controller/UsersControllerTest.php
@@ -1,99 +1,97 @@
<?php
+
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@owncloud.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author michag86 <micha_g@arcor.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Tom Needham <tom@owncloud.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/>
- *
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Provisioning_API\Tests\Controller;
use Exception;
-use OC\Accounts\AccountManager;
+use OC\Authentication\Token\RemoteWipe;
use OC\Group\Manager;
-use OCP\App\IAppManager;
-use OCP\AppFramework\OCS\OCSException;
-use OCP\Mail\IEMailTemplate;
-use OC\Settings\Mailer\NewUserMailHelper;
+use OC\KnownUser\KnownUserService;
+use OC\PhoneNumberUtil;
use OC\SubAdmin;
use OCA\Provisioning_API\Controller\UsersController;
+use OCA\Settings\Mailer\NewUserMailHelper;
+use OCP\Accounts\IAccount;
+use OCP\Accounts\IAccountManager;
+use OCP\Accounts\IAccountProperty;
+use OCP\Accounts\IAccountPropertyCollection;
+use OCP\App\IAppManager;
use OCP\AppFramework\Http\DataResponse;
-use OCP\Defaults;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\IRootFolder;
+use OCP\Group\ISubAdmin;
use OCP\IConfig;
use OCP\IGroup;
-use OCP\ILogger;
use OCP\IL10N;
+use OCP\IPhoneNumberUtil;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory;
-use OCP\Mail\IMailer;
-use PHPUnit_Framework_MockObject_MockObject;
+use OCP\Mail\IEMailTemplate;
+use OCP\Security\Events\GenerateSecurePasswordEvent;
+use OCP\Security\ISecureRandom;
+use OCP\User\Backend\ISetDisplayNameBackend;
+use OCP\UserInterface;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use RuntimeException;
use Test\TestCase;
class UsersControllerTest extends TestCase {
-
- /** @var IUserManager|PHPUnit_Framework_MockObject_MockObject */
- protected $userManager;
- /** @var IConfig|PHPUnit_Framework_MockObject_MockObject */
- protected $config;
- /** @var IAppManager|PHPUnit_Framework_MockObject_MockObject */
- protected $appManager;
- /** @var Manager|PHPUnit_Framework_MockObject_MockObject */
- protected $groupManager;
- /** @var IUserSession|PHPUnit_Framework_MockObject_MockObject */
- protected $userSession;
- /** @var ILogger|PHPUnit_Framework_MockObject_MockObject */
- protected $logger;
- /** @var UsersController|PHPUnit_Framework_MockObject_MockObject */
- protected $api;
- /** @var AccountManager|PHPUnit_Framework_MockObject_MockObject */
- protected $accountManager;
- /** @var IRequest|PHPUnit_Framework_MockObject_MockObject */
- protected $request;
- /** @var IFactory|PHPUnit_Framework_MockObject_MockObject */
- private $l10nFactory;
- /** @var NewUserMailHelper|PHPUnit_Framework_MockObject_MockObject */
- private $newUserMailHelper;
-
- protected function setUp() {
+ protected IUserManager&MockObject $userManager;
+ protected IConfig&MockObject $config;
+ protected Manager&MockObject $groupManager;
+ protected IUserSession&MockObject $userSession;
+ protected LoggerInterface&MockObject $logger;
+ protected UsersController&MockObject $api;
+ protected IAccountManager&MockObject $accountManager;
+ protected ISubAdmin&MockObject $subAdminManager;
+ protected IURLGenerator&MockObject $urlGenerator;
+ protected IRequest&MockObject $request;
+ private IFactory&MockObject $l10nFactory;
+ private NewUserMailHelper&MockObject $newUserMailHelper;
+ private ISecureRandom&MockObject $secureRandom;
+ private RemoteWipe&MockObject $remoteWipe;
+ private KnownUserService&MockObject $knownUserService;
+ private IEventDispatcher&MockObject $eventDispatcher;
+ private IRootFolder $rootFolder;
+ private IPhoneNumberUtil $phoneNumberUtil;
+ private IAppManager $appManager;
+
+ protected function setUp(): void {
parent::setUp();
$this->userManager = $this->createMock(IUserManager::class);
$this->config = $this->createMock(IConfig::class);
- $this->appManager = $this->createMock(IAppManager::class);
$this->groupManager = $this->createMock(Manager::class);
$this->userSession = $this->createMock(IUserSession::class);
- $this->logger = $this->createMock(ILogger::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
$this->request = $this->createMock(IRequest::class);
- $this->accountManager = $this->createMock(AccountManager::class);
+ $this->accountManager = $this->createMock(IAccountManager::class);
+ $this->subAdminManager = $this->createMock(ISubAdmin::class);
+ $this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->l10nFactory = $this->createMock(IFactory::class);
$this->newUserMailHelper = $this->createMock(NewUserMailHelper::class);
+ $this->secureRandom = $this->createMock(ISecureRandom::class);
+ $this->remoteWipe = $this->createMock(RemoteWipe::class);
+ $this->knownUserService = $this->createMock(KnownUserService::class);
+ $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
+ $this->phoneNumberUtil = new PhoneNumberUtil();
+ $this->appManager = $this->createMock(IAppManager::class);
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+
+ $l10n = $this->createMock(IL10N::class);
+ $l10n->method('t')->willReturnCallback(fn (string $txt, array $replacement = []) => sprintf($txt, ...$replacement));
+ $this->l10nFactory->method('get')->with('provisioning_api')->willReturn($l10n);
$this->api = $this->getMockBuilder(UsersController::class)
->setConstructorArgs([
@@ -101,41 +99,50 @@ class UsersControllerTest extends TestCase {
$this->request,
$this->userManager,
$this->config,
- $this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
- $this->logger,
+ $this->subAdminManager,
$this->l10nFactory,
- $this->newUserMailHelper
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->logger,
+ $this->newUserMailHelper,
+ $this->secureRandom,
+ $this->remoteWipe,
+ $this->knownUserService,
+ $this->eventDispatcher,
+ $this->phoneNumberUtil,
+ $this->appManager,
])
- ->setMethods(['fillStorageInfo'])
+ ->onlyMethods(['fillStorageInfo'])
->getMock();
}
- public function testGetUsersAsAdmin() {
+ public function testGetUsersAsAdmin(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->userManager
->expects($this->once())
->method('search')
- ->with('MyCustomSearch', null, null)
- ->will($this->returnValue(['Admin' => [], 'Foo' => [], 'Bar' => []]));
+ ->with('MyCustomSearch')
+ ->willReturn(['Admin' => [], 'Foo' => [], 'Bar' => []]);
- $expected = ['users' => [
+ $expected = [
+ 'users' => [
'Admin',
'Foo',
'Bar',
@@ -144,56 +151,55 @@ class UsersControllerTest extends TestCase {
$this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
}
- public function testGetUsersAsSubAdmin() {
+ public function testGetUsersAsSubAdmin(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$firstGroup = $this->getMockBuilder('OCP\IGroup')
->disableOriginalConstructor()
->getMock();
$firstGroup
->expects($this->once())
->method('getGID')
- ->will($this->returnValue('FirstGroup'));
+ ->willReturn('FirstGroup');
$secondGroup = $this->getMockBuilder('OCP\IGroup')
->disableOriginalConstructor()
->getMock();
$secondGroup
->expects($this->once())
->method('getGID')
- ->will($this->returnValue('SecondGroup'));
+ ->willReturn('SecondGroup');
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isSubAdmin')
->with($loggedInUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$subAdminManager
->expects($this->once())
->method('getSubAdminsGroups')
->with($loggedInUser)
- ->will($this->returnValue([$firstGroup, $secondGroup]));
+ ->willReturn([$firstGroup, $secondGroup]);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->any())
- ->method('displayNamesInGroup')
- ->will($this->onConsecutiveCalls(['AnotherUserInTheFirstGroup' => []], ['UserInTheSecondGroup' => []]));
+ ->method('displayNamesInGroup')->willReturnOnConsecutiveCalls(['AnotherUserInTheFirstGroup' => []], ['UserInTheSecondGroup' => []]);
$expected = [
'users' => [
@@ -204,16 +210,141 @@ class UsersControllerTest extends TestCase {
$this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- */
- public function testAddUserAlreadyExisting() {
+ private function createUserMock(string $uid, bool $enabled): MockObject&IUser {
+ $mockUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mockUser
+ ->method('getUID')
+ ->willReturn($uid);
+ $mockUser
+ ->method('isEnabled')
+ ->willReturn($enabled);
+ return $mockUser;
+ }
+
+ public function testGetDisabledUsersAsAdmin(): void {
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->once())
+ ->method('getUID')
+ ->willReturn('admin');
+ $this->userSession
+ ->expects($this->atLeastOnce())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->willReturn(true);
+ $this->userManager
+ ->expects($this->once())
+ ->method('getDisabledUsers')
+ ->with(3, 0, 'MyCustomSearch')
+ ->willReturn([
+ $this->createUserMock('admin', false),
+ $this->createUserMock('foo', false),
+ $this->createUserMock('bar', false),
+ ]);
+
+ $expected = [
+ 'users' => [
+ 'admin' => ['id' => 'admin'],
+ 'foo' => ['id' => 'foo'],
+ 'bar' => ['id' => 'bar'],
+ ],
+ ];
+ $this->assertEquals($expected, $this->api->getDisabledUsersDetails('MyCustomSearch', 3)->getData());
+ }
+
+ public function testGetDisabledUsersAsSubAdmin(): void {
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->once())
+ ->method('getUID')
+ ->willReturn('subadmin');
+ $this->userSession
+ ->expects($this->atLeastOnce())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->willReturn(false);
+ $firstGroup = $this->getMockBuilder('OCP\IGroup')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $secondGroup = $this->getMockBuilder('OCP\IGroup')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
+ ->disableOriginalConstructor()->getMock();
+ $subAdminManager
+ ->expects($this->once())
+ ->method('isSubAdmin')
+ ->with($loggedInUser)
+ ->willReturn(true);
+ $subAdminManager
+ ->expects($this->once())
+ ->method('getSubAdminsGroups')
+ ->with($loggedInUser)
+ ->willReturn([$firstGroup, $secondGroup]);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('getSubAdmin')
+ ->willReturn($subAdminManager);
+ $this->groupManager
+ ->expects($this->never())
+ ->method('displayNamesInGroup');
+
+ $firstGroup
+ ->expects($this->once())
+ ->method('searchUsers')
+ ->with('MyCustomSearch')
+ ->willReturn([
+ $this->createUserMock('user1', false),
+ $this->createUserMock('bob', true),
+ $this->createUserMock('user2', false),
+ $this->createUserMock('alice', true),
+ ]);
+
+ $secondGroup
+ ->expects($this->once())
+ ->method('searchUsers')
+ ->with('MyCustomSearch')
+ ->willReturn([
+ $this->createUserMock('user2', false),
+ $this->createUserMock('joe', true),
+ $this->createUserMock('user3', false),
+ $this->createUserMock('jim', true),
+ $this->createUserMock('john', true),
+ ]);
+
+
+ $expected = [
+ 'users' => [
+ 'user1' => ['id' => 'user1'],
+ 'user2' => ['id' => 'user2'],
+ 'user3' => ['id' => 'user3'],
+ ],
+ ];
+ $this->assertEquals($expected, $this->api->getDisabledUsersDetails('MyCustomSearch', 3)->getData());
+ }
+
+
+ public function testAddUserAlreadyExisting(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(102);
+
$this->userManager
->expects($this->once())
->method('userExists')
->with('AlreadyExistingUser')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->logger
->expects($this->once())
->method('error')
@@ -222,28 +353,28 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('adminUser'));
+ ->willReturn('adminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('adminUser')
->willReturn(true);
- $this->api->addUser('AlreadyExistingUser', null, null);
+ $this->api->addUser('AlreadyExistingUser', 'password', '', '', []);
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 104
- * @expectedExceptionMessage group NonExistingGroup does not exist
- */
- public function testAddUserNonExistingGroup() {
+
+ public function testAddUserNonExistingGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Group NonExistingGroup does not exist');
+ $this->expectExceptionCode(104);
+
$this->userManager
->expects($this->once())
->method('userExists')
@@ -253,13 +384,13 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('adminUser'));
+ ->willReturn('adminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -271,15 +402,15 @@ class UsersControllerTest extends TestCase {
->with('NonExistingGroup')
->willReturn(false);
- $this->api->addUser('NewUser', 'pass', ['NonExistingGroup']);
+ $this->api->addUser('NewUser', 'pass', '', '', ['NonExistingGroup']);
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 104
- * @expectedExceptionMessage group NonExistingGroup does not exist
- */
- public function testAddUserExistingGroupNonExistingGroup() {
+
+ public function testAddUserExistingGroupNonExistingGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Group NonExistingGroup does not exist');
+ $this->expectExceptionCode(104);
+
$this->userManager
->expects($this->once())
->method('userExists')
@@ -289,13 +420,13 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('adminUser'));
+ ->willReturn('adminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -304,28 +435,25 @@ class UsersControllerTest extends TestCase {
$this->groupManager
->expects($this->exactly(2))
->method('groupExists')
- ->withConsecutive(
- ['ExistingGroup'],
- ['NonExistingGroup']
- )
- ->will($this->returnValueMap([
+ ->willReturnMap([
['ExistingGroup', true],
['NonExistingGroup', false]
- ]));
+ ]);
- $this->api->addUser('NewUser', 'pass', ['ExistingGroup', 'NonExistingGroup']);
+ $this->api->addUser('NewUser', 'pass', '', '', ['ExistingGroup', 'NonExistingGroup']);
}
- public function testAddUserSuccessful() {
+ public function testAddUserSuccessful(): void {
$this->userManager
->expects($this->once())
->method('userExists')
->with('NewUser')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->userManager
->expects($this->once())
->method('createUser')
- ->with('NewUser', 'PasswordOfTheNewUser');
+ ->with('NewUser', 'PasswordOfTheNewUser')
+ ->willReturn($this->createMock(IUser::class));
$this->logger
->expects($this->once())
->method('info')
@@ -334,39 +462,343 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('adminUser');
+ $this->userSession
->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->with('adminUser')
+ ->willReturn(true);
+
+ $this->assertTrue(key_exists(
+ 'id',
+ $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()
+ ));
+ }
+
+ public function testAddUserSuccessfulWithDisplayName(): void {
+ /**
+ * @var UserController
+ */
+ $api = $this->getMockBuilder(UsersController::class)
+ ->setConstructorArgs([
+ 'provisioning_api',
+ $this->request,
+ $this->userManager,
+ $this->config,
+ $this->groupManager,
+ $this->userSession,
+ $this->accountManager,
+ $this->subAdminManager,
+ $this->l10nFactory,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->logger,
+ $this->newUserMailHelper,
+ $this->secureRandom,
+ $this->remoteWipe,
+ $this->knownUserService,
+ $this->eventDispatcher,
+ $this->phoneNumberUtil,
+ $this->appManager,
+ ])
+ ->onlyMethods(['editUser'])
+ ->getMock();
+
+ $this->userManager
+ ->expects($this->once())
+ ->method('userExists')
+ ->with('NewUser')
+ ->willReturn(false);
+ $this->userManager
+ ->expects($this->once())
+ ->method('createUser')
+ ->with('NewUser', 'PasswordOfTheNewUser')
+ ->willReturn($this->createMock(IUser::class));
+ $this->logger
+ ->expects($this->once())
+ ->method('info')
+ ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('adminUser');
+ $this->userSession
+ ->expects($this->any())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->with('adminUser')
+ ->willReturn(true);
+ $api
+ ->expects($this->once())
+ ->method('editUser')
+ ->with('NewUser', 'display', 'DisplayNameOfTheNewUser');
+
+ $this->assertTrue(key_exists(
+ 'id',
+ $api->addUser('NewUser', 'PasswordOfTheNewUser', 'DisplayNameOfTheNewUser')->getData()
+ ));
+ }
+
+ public function testAddUserSuccessfulGenerateUserID(): void {
+ $this->config
+ ->expects($this->any())
+ ->method('getAppValue')
+ ->willReturnCallback(function ($appid, $key, $default) {
+ if ($key === 'newUser.generateUserID') {
+ return 'yes';
+ }
+ return null;
+ });
+ $this->userManager
+ ->expects($this->any())
+ ->method('userExists')
+ ->with($this->anything())
+ ->willReturn(false);
+ $this->userManager
+ ->expects($this->once())
+ ->method('createUser')
+ ->with($this->anything(), 'PasswordOfTheNewUser')
+ ->willReturn($this->createMock(IUser::class));
+ $this->logger
+ ->expects($this->once())
+ ->method('info')
+ ->with($this->stringStartsWith('Successful addUser call with userid: '), ['app' => 'ocs_api']);
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('adminUser');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->with('adminUser')
+ ->willReturn(true);
+ $this->secureRandom->expects($this->any())
+ ->method('generate')
+ ->with(10)
+ ->willReturnCallback(function () {
+ return (string)rand(100000000, 999999999);
+ });
+
+ $this->assertTrue(key_exists(
+ 'id',
+ $this->api->addUser('', 'PasswordOfTheNewUser')->getData()
+ ));
+ }
+
+ public function testAddUserSuccessfulGeneratePassword(): void {
+ $this->userManager
+ ->expects($this->once())
+ ->method('userExists')
+ ->with('NewUser')
+ ->willReturn(false);
+ $newUser = $this->createMock(IUser::class);
+ $newUser->expects($this->once())
+ ->method('setSystemEMailAddress');
+ $this->userManager
+ ->expects($this->once())
+ ->method('createUser')
+ ->willReturn($newUser);
+ $this->logger
+ ->expects($this->once())
+ ->method('info')
+ ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('adminUser'));
+ ->willReturn('adminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('adminUser')
->willReturn(true);
+ $this->eventDispatcher
+ ->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new GenerateSecurePasswordEvent());
- $this->assertEquals([], $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData());
+ $this->assertTrue(key_exists(
+ 'id',
+ $this->api->addUser('NewUser', '', '', 'foo@bar')->getData()
+ ));
}
- public function testAddUserExistingGroup() {
+ public function testAddUserSuccessfulLowercaseEmail(): void {
$this->userManager
->expects($this->once())
->method('userExists')
->with('NewUser')
->willReturn(false);
+ $newUser = $this->createMock(IUser::class);
+ $newUser->expects($this->once())
+ ->method('setSystemEMailAddress')
+ ->with('foo@bar.com');
+ $this->userManager
+ ->expects($this->once())
+ ->method('createUser')
+ ->willReturn($newUser);
+ $this->logger
+ ->expects($this->once())
+ ->method('info')
+ ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('adminUser');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
->expects($this->once())
+ ->method('isAdmin')
+ ->with('adminUser')
+ ->willReturn(true);
+ $this->eventDispatcher
+ ->expects($this->once())
+ ->method('dispatchTyped')
+ ->with(new GenerateSecurePasswordEvent());
+
+ $this->assertTrue(key_exists(
+ 'id',
+ $this->api->addUser('NewUser', '', '', 'fOo@BaR.CoM')->getData()
+ ));
+ }
+
+
+ public function testAddUserFailedToGenerateUserID(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Could not create non-existing user ID');
+ $this->expectExceptionCode(111);
+
+ $this->config
+ ->expects($this->any())
+ ->method('getAppValue')
+ ->willReturnCallback(function ($appid, $key, $default) {
+ if ($key === 'newUser.generateUserID') {
+ return 'yes';
+ }
+ return null;
+ });
+ $this->userManager
+ ->expects($this->any())
+ ->method('userExists')
+ ->with($this->anything())
+ ->willReturn(true);
+ $this->userManager
+ ->expects($this->never())
+ ->method('createUser');
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('adminUser'));
+ ->willReturn('adminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->with('adminUser')
+ ->willReturn(true);
+
+ $this->api->addUser('', 'PasswordOfTheNewUser')->getData();
+ }
+
+
+ public function testAddUserEmailRequired(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Required email address was not provided');
+ $this->expectExceptionCode(110);
+
+ $this->config
+ ->expects($this->any())
+ ->method('getAppValue')
+ ->willReturnCallback(function ($appid, $key, $default) {
+ if ($key === 'newUser.requireEmail') {
+ return 'yes';
+ }
+ return null;
+ });
+ $this->userManager
+ ->expects($this->once())
+ ->method('userExists')
+ ->with('NewUser')
+ ->willReturn(false);
+ $this->userManager
+ ->expects($this->never())
+ ->method('createUser');
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('adminUser');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('isAdmin')
+ ->with('adminUser')
+ ->willReturn(true);
+
+ $this->assertTrue(key_exists(
+ 'id',
+ $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()
+ ));
+ }
+
+ public function testAddUserExistingGroup(): void {
+ $this->userManager
+ ->expects($this->once())
+ ->method('userExists')
+ ->with('NewUser')
+ ->willReturn(false);
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('adminUser');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -397,48 +829,60 @@ class UsersControllerTest extends TestCase {
->method('get')
->with('ExistingGroup')
->willReturn($group);
+
+ $calls = [
+ ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
+ ['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']],
+ ];
$this->logger
->expects($this->exactly(2))
->method('info')
- ->withConsecutive(
- ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
- ['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']]
- );
+ ->willReturnCallback(function () use (&$calls): void {
+ $expected = array_shift($calls);
+ $this->assertEquals($expected, func_get_args());
+ });
- $this->assertEquals([], $this->api->addUser('NewUser', 'PasswordOfTheNewUser', ['ExistingGroup'])->getData());
+ $this->assertArrayHasKey('id', $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage Bad request
- */
- public function testAddUserUnsuccessful() {
+
+ public function testAddUserUnsuccessful(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Bad request');
+ $this->expectExceptionCode(101);
+
+ $exception = new Exception('User backend not found.');
$this->userManager
->expects($this->once())
->method('userExists')
->with('NewUser')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->userManager
->expects($this->once())
->method('createUser')
->with('NewUser', 'PasswordOfTheNewUser')
- ->will($this->throwException(new Exception('User backend not found.')));
+ ->willThrowException($exception);
$this->logger
->expects($this->once())
->method('error')
- ->with('Failed addUser attempt with exception: User backend not found.', ['app' => 'ocs_api']);
+ ->with(
+ 'Failed addUser attempt with exception.',
+ [
+ 'app' => 'ocs_api',
+ 'exception' => $exception
+ ]
+ );
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('adminUser'));
+ ->willReturn('adminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -448,23 +892,23 @@ class UsersControllerTest extends TestCase {
$this->api->addUser('NewUser', 'PasswordOfTheNewUser');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 106
- * @expectedExceptionMessage no group specified (required for subadmins)
- */
- public function testAddUserAsSubAdminNoGroup() {
+
+ public function testAddUserAsSubAdminNoGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('No group specified (required for sub-admins)');
+ $this->expectExceptionCode(106);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('regularUser'));
+ ->willReturn('regularUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -478,26 +922,26 @@ class UsersControllerTest extends TestCase {
->with()
->willReturn($subAdminManager);
- $this->api->addUser('NewUser', 'PasswordOfTheNewUser', null);
+ $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', []);
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 105
- * @expectedExceptionMessage insufficient privileges for group ExistingGroup
- */
- public function testAddUserAsSubAdminValidGroupNotSubAdmin() {
+
+ public function testAddUserAsSubAdminValidGroupNotSubAdmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Insufficient privileges for group ExistingGroup');
+ $this->expectExceptionCode(105);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('regularUser'));
+ ->willReturn('regularUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -527,10 +971,10 @@ class UsersControllerTest extends TestCase {
->with('ExistingGroup')
->willReturn(true);
- $this->api->addUser('NewUser', 'PasswordOfTheNewUser', ['ExistingGroup'])->getData();
+ $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData();
}
- public function testAddUserAsSubAdminExistingGroups() {
+ public function testAddUserAsSubAdminExistingGroups(): void {
$this->userManager
->expects($this->once())
->method('userExists')
@@ -540,13 +984,13 @@ class UsersControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('subAdminUser'));
+ ->willReturn('subAdminUser');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
@@ -555,11 +999,10 @@ class UsersControllerTest extends TestCase {
$this->groupManager
->expects($this->exactly(2))
->method('groupExists')
- ->withConsecutive(
- ['ExistingGroup1'],
- ['ExistingGroup2']
- )
- ->willReturn(true);
+ ->willReturnMap([
+ ['ExistingGroup1', true],
+ ['ExistingGroup2', true]
+ ]);
$user = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
@@ -585,24 +1028,23 @@ class UsersControllerTest extends TestCase {
$this->groupManager
->expects($this->exactly(4))
->method('get')
- ->withConsecutive(
- ['ExistingGroup1'],
- ['ExistingGroup2'],
- ['ExistingGroup1'],
- ['ExistingGroup2']
- )
- ->will($this->returnValueMap([
+ ->willReturnMap([
['ExistingGroup1', $existingGroup1],
['ExistingGroup2', $existingGroup2]
- ]));
+ ]);
+
+ $calls = [
+ ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
+ ['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']],
+ ['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']],
+ ];
$this->logger
->expects($this->exactly(3))
->method('info')
- ->withConsecutive(
- ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
- ['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']],
- ['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']]
- );
+ ->willReturnCallback(function () use (&$calls): void {
+ $expected = array_shift($calls);
+ $this->assertEquals($expected, func_get_args());
+ });
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$this->groupManager
@@ -612,160 +1054,219 @@ class UsersControllerTest extends TestCase {
$subAdminManager
->expects($this->exactly(2))
->method('isSubAdminOfGroup')
- ->withConsecutive(
- [$loggedInUser, $existingGroup1],
- [$loggedInUser, $existingGroup2]
- )
- ->willReturn(true);
+ ->willReturnMap([
+ [$loggedInUser, $existingGroup1, true],
+ [$loggedInUser, $existingGroup2, true],
+ ]);
- $this->assertEquals([], $this->api->addUser('NewUser', 'PasswordOfTheNewUser', ['ExistingGroup1', 'ExistingGroup2'])->getData());
+ $this->assertArrayHasKey('id', $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup1', 'ExistingGroup2'])->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 998
- * @expectedExceptionMessage The requested user could not be found
- */
- public function testGetUserTargetDoesNotExist() {
+
+ public function testGetUserTargetDoesNotExist(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('User does not exist');
+ $this->expectExceptionCode(404);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
- ->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->getUser('UserToGet');
}
- public function testGetUserDataAsAdmin() {
- $group = $this->getMockBuilder(IGroup::class)
+ public function testGetUserDataAsAdmin(): void {
+ $group0 = $this->createMock(IGroup::class);
+ $group1 = $this->createMock(IGroup::class);
+ $group2 = $this->createMock(IGroup::class);
+ $group3 = $this->createMock(IGroup::class);
+ $loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
- $loggedInUser = $this->getMockBuilder(IUser::class)
+ $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$targetUser->expects($this->once())
- ->method('getEMailAddress')
- ->willReturn('demo@owncloud.org');
+ ->method('getSystemEMailAddress')
+ ->willReturn('demo@nextcloud.com');
$this->userSession
- ->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
- ->expects($this->once())
->method('get')
- ->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->with('UID')
+ ->willReturn($targetUser);
$this->groupManager
- ->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->any())
->method('getUserGroups')
- ->willReturn([$group, $group, $group]);
- $group->expects($this->at(0))
- ->method('getDisplayName')
+ ->willReturn([$group0, $group1, $group2]);
+ $this->groupManager
+ ->expects($this->once())
+ ->method('getSubAdmin')
+ ->willReturn($subAdminManager);
+ $subAdminManager
+ ->expects($this->once())
+ ->method('getSubAdminsGroups')
+ ->willReturn([$group3]);
+ $group0->expects($this->once())
+ ->method('getGID')
->willReturn('group0');
- $group->expects($this->at(1))
- ->method('getDisplayName')
+ $group1->expects($this->once())
+ ->method('getGID')
->willReturn('group1');
- $group->expects($this->at(2))
- ->method('getDisplayName')
+ $group2->expects($this->once())
+ ->method('getGID')
->willReturn('group2');
- $this->accountManager->expects($this->any())->method('getUser')
- ->with($targetUser)
- ->willReturn(
- [
- AccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
- AccountManager::PROPERTY_PHONE => ['value' => 'phone'],
- AccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
- AccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
- ]
- );
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('UID', 'core', 'enabled', 'true')
- ->will($this->returnValue('true'));
+ $group3->expects($this->once())
+ ->method('getGID')
+ ->willReturn('group3');
+
+ $this->mockAccount($targetUser, [
+ IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
+ IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
+ IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
+ IAccountManager::PROPERTY_BLUESKY => ['value' => 'bluesky'],
+ IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
+ IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
+ IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
+ IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
+ IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
+ IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
+ IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
+ IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
+ ]);
$this->config
- ->expects($this->at(1))
->method('getUserValue')
- ->with('UID', 'core', 'lang')
- ->will($this->returnValue('de'));
+ ->willReturnMap([
+ ['UID', 'core', 'enabled', 'true', 'true'],
+ ]);
$this->api
->expects($this->once())
->method('fillStorageInfo')
- ->with('UID')
- ->will($this->returnValue(['DummyValue']));
+ ->with($targetUser)
+ ->willReturn(['DummyValue']);
+
+ $backend = $this->createMock(UserInterface::class);
+ $backend->expects($this->any())
+ ->method('implementsActions')
+ ->willReturn(true);
+
$targetUser
->expects($this->once())
->method('getDisplayName')
- ->will($this->returnValue('Demo User'));
+ ->willReturn('Demo User');
+ $targetUser
+ ->expects($this->once())
+ ->method('getHome')
+ ->willReturn('/var/www/newtcloud/data/UID');
+ $targetUser
+ ->expects($this->exactly(2))
+ ->method('getLastLogin')
+ ->willReturn(1521191471);
+ $targetUser
+ ->expects($this->once())
+ ->method('getFirstLogin')
+ ->willReturn(1511191471);
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackendClassName')
+ ->willReturn('Database');
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackend')
+ ->willReturn($backend);
$targetUser
- ->expects($this->exactly(4))
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('getUserLanguage')
+ ->with($targetUser)
+ ->willReturn('de');
$expected = [
'id' => 'UID',
- 'enabled' => 'true',
+ 'enabled' => true,
+ 'storageLocation' => '/var/www/newtcloud/data/UID',
+ 'firstLoginTimestamp' => 1511191471,
+ 'lastLoginTimestamp' => 1521191471,
+ 'lastLogin' => 1521191471000,
+ 'backend' => 'Database',
+ 'subadmin' => ['group3'],
'quota' => ['DummyValue'],
- 'email' => 'demo@owncloud.org',
+ 'email' => 'demo@nextcloud.com',
'displayname' => 'Demo User',
+ 'display-name' => 'Demo User',
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
+ 'bluesky' => 'bluesky',
+ 'fediverse' => 'fediverse',
'groups' => ['group0', 'group1', 'group2'],
'language' => 'de',
+ 'locale' => null,
+ 'backendCapabilities' => [
+ 'setDisplayName' => true,
+ 'setPassword' => true,
+ ],
+ 'additional_mail' => [],
+ 'organisation' => 'organisation',
+ 'role' => 'role',
+ 'headline' => 'headline',
+ 'biography' => 'biography',
+ 'profile_enabled' => '1',
+ 'notify_email' => null,
+ 'manager' => '',
+ 'pronouns' => 'they/them',
];
- $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UserToGet']));
+ $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
- public function testGetUserDataAsSubAdminAndUserIsAccessible() {
+ public function testGetUserDataAsSubAdminAndUserIsAccessible(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->once())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$targetUser
- ->expects($this->once())
- ->method('getEMailAddress')
- ->willReturn('demo@owncloud.org');
- $this->userSession
->expects($this->once())
+ ->method('getSystemEMailAddress')
+ ->willReturn('demo@nextcloud.com');
+ $this->userSession
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
- ->expects($this->once())
->method('get')
- ->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->with('UID')
+ ->willReturn($targetUser);
$this->groupManager
- ->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->any())
->method('getUserGroups')
@@ -777,91 +1278,146 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
- $this->groupManager
+ ->willReturn(true);
+ $subAdminManager
->expects($this->once())
+ ->method('getSubAdminsGroups')
+ ->willReturn([]);
+ $this->groupManager
+ ->expects($this->exactly(2))
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('UID', 'core', 'enabled', 'true')
- ->will($this->returnValue('true'));
+ ->willReturn($subAdminManager);
$this->config
- ->expects($this->at(1))
->method('getUserValue')
- ->with('UID', 'core', 'lang')
- ->will($this->returnValue('da'));
+ ->willReturnMap([
+ ['UID', 'core', 'enabled', 'true', 'true'],
+ ]);
$this->api
->expects($this->once())
->method('fillStorageInfo')
- ->with('UID')
- ->will($this->returnValue(['DummyValue']));
+ ->with($targetUser)
+ ->willReturn(['DummyValue']);
+
+ $backend = $this->createMock(UserInterface::class);
+ $backend->expects($this->any())
+ ->method('implementsActions')
+ ->willReturn(true);
+
$targetUser
->expects($this->once())
->method('getDisplayName')
- ->will($this->returnValue('Demo User'));
+ ->willReturn('Demo User');
+ $targetUser
+ ->expects($this->never())
+ ->method('getHome');
+ $targetUser
+ ->expects($this->exactly(2))
+ ->method('getLastLogin')
+ ->willReturn(1521191471);
+ $targetUser
+ ->expects($this->once())
+ ->method('getFirstLogin')
+ ->willReturn(1511191471);
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackendClassName')
+ ->willReturn('Database');
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackend')
+ ->willReturn($backend);
$targetUser
- ->expects($this->exactly(4))
->method('getUID')
- ->will($this->returnValue('UID'));
- $this->accountManager->expects($this->any())->method('getUser')
+ ->willReturn('UID');
+
+ $this->mockAccount($targetUser, [
+ IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
+ IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
+ IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
+ IAccountManager::PROPERTY_BLUESKY => ['value' => 'bluesky'],
+ IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
+ IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
+ IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
+ IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
+ IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
+ IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
+ IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
+ IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
+ ]);
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('getUserLanguage')
->with($targetUser)
- ->willReturn(
- [
- AccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
- AccountManager::PROPERTY_PHONE => ['value' => 'phone'],
- AccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
- AccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
- ]
- );
+ ->willReturn('da');
$expected = [
'id' => 'UID',
- 'enabled' => 'true',
+ 'enabled' => true,
+ 'firstLoginTimestamp' => 1511191471,
+ 'lastLoginTimestamp' => 1521191471,
+ 'lastLogin' => 1521191471000,
+ 'backend' => 'Database',
+ 'subadmin' => [],
'quota' => ['DummyValue'],
- 'email' => 'demo@owncloud.org',
+ 'email' => 'demo@nextcloud.com',
'displayname' => 'Demo User',
+ 'display-name' => 'Demo User',
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
+ 'bluesky' => 'bluesky',
+ 'fediverse' => 'fediverse',
'groups' => [],
'language' => 'da',
+ 'locale' => null,
+ 'backendCapabilities' => [
+ 'setDisplayName' => true,
+ 'setPassword' => true,
+ ],
+ 'additional_mail' => [],
+ 'organisation' => 'organisation',
+ 'role' => 'role',
+ 'headline' => 'headline',
+ 'biography' => 'biography',
+ 'profile_enabled' => '1',
+ 'notify_email' => null,
+ 'manager' => '',
+ 'pronouns' => 'they/them',
];
- $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UserToGet']));
+ $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testGetUserDataAsSubAdminAndUserIsNotAccessible() {
+
+ public function testGetUserDataAsSubAdminAndUserIsNotAccessible(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->exactly(2))
+ ->expects($this->exactly(4))
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
- ->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -869,40 +1425,36 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
- $this->invokePrivate($this->api, 'getUserData', ['UserToGet']);
+ $this->invokePrivate($this->api, 'getUser', ['UserToGet']);
}
- public function testGetUserDataAsSubAdminSelfLookup() {
+ public function testGetUserDataAsSubAdminSelfLookup(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
- ->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
- ->expects($this->once())
->method('get')
- ->with('subadmin')
- ->will($this->returnValue($targetUser));
+ ->with('UID')
+ ->willReturn($targetUser);
$this->groupManager
- ->expects($this->once())
->method('isAdmin')
->with('UID')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -910,11 +1462,15 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(false));
- $this->groupManager
+ ->willReturn(false);
+ $subAdminManager
->expects($this->once())
+ ->method('getSubAdminsGroups')
+ ->willReturn([]);
+ $this->groupManager
+ ->expects($this->exactly(2))
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->any())
->method('getUserGroups')
@@ -922,168 +1478,600 @@ class UsersControllerTest extends TestCase {
$this->api
->expects($this->once())
->method('fillStorageInfo')
- ->with('UID')
- ->will($this->returnValue(['DummyValue']));
+ ->with($targetUser)
+ ->willReturn(['DummyValue']);
+
+ $backend = $this->createMock(UserInterface::class);
+ $backend->expects($this->atLeastOnce())
+ ->method('implementsActions')
+ ->willReturn(false);
+
$targetUser
->expects($this->once())
->method('getDisplayName')
- ->will($this->returnValue('Subadmin User'));
+ ->willReturn('Subadmin User');
$targetUser
->expects($this->once())
- ->method('getEMailAddress')
- ->will($this->returnValue('subadmin@owncloud.org'));
+ ->method('getSystemEMailAddress')
+ ->willReturn('subadmin@nextcloud.com');
$targetUser
- ->expects($this->exactly(4))
->method('getUID')
- ->will($this->returnValue('UID'));
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('UID', 'core', 'lang')
- ->will($this->returnValue('ru'));
- $this->accountManager->expects($this->any())->method('getUser')
+ ->willReturn('UID');
+ $targetUser
+ ->expects($this->never())
+ ->method('getHome');
+ $targetUser
+ ->expects($this->exactly(2))
+ ->method('getLastLogin')
+ ->willReturn(1521191471);
+ $targetUser
+ ->expects($this->once())
+ ->method('getFirstLogin')
+ ->willReturn(1511191471);
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackendClassName')
+ ->willReturn('Database');
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackend')
+ ->willReturn($backend);
+ $this->mockAccount($targetUser, [
+ IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
+ IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
+ IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
+ IAccountManager::PROPERTY_BLUESKY => ['value' => 'bluesky'],
+ IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
+ IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
+ IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
+ IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
+ IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
+ IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
+ IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
+ IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
+ ]);
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('getUserLanguage')
->with($targetUser)
- ->willReturn(
- [
- AccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
- AccountManager::PROPERTY_PHONE => ['value' => 'phone'],
- AccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
- AccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
- ]
- );
+ ->willReturn('ru');
$expected = [
'id' => 'UID',
+ 'firstLoginTimestamp' => 1511191471,
+ 'lastLoginTimestamp' => 1521191471,
+ 'lastLogin' => 1521191471000,
+ 'backend' => 'Database',
+ 'subadmin' => [],
'quota' => ['DummyValue'],
- 'email' => 'subadmin@owncloud.org',
+ 'email' => 'subadmin@nextcloud.com',
'displayname' => 'Subadmin User',
+ 'display-name' => 'Subadmin User',
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
+ 'bluesky' => 'bluesky',
+ 'fediverse' => 'fediverse',
'groups' => [],
'language' => 'ru',
+ 'locale' => null,
+ 'backendCapabilities' => [
+ 'setDisplayName' => false,
+ 'setPassword' => false,
+ ],
+ 'additional_mail' => [],
+ 'organisation' => 'organisation',
+ 'role' => 'role',
+ 'headline' => 'headline',
+ 'biography' => 'biography',
+ 'profile_enabled' => '1',
+ 'notify_email' => null,
+ 'manager' => '',
+ 'pronouns' => 'they/them',
+ ];
+ $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
+ }
+
+ public static function dataSearchByPhoneNumbers(): array {
+ return [
+ 'Invalid country' => ['Not a country code', ['12345' => ['NaN']], 400, null, null, []],
+ 'No number to search' => ['DE', ['12345' => ['NaN']], 200, null, null, []],
+ 'Valid number but no match' => ['DE', ['12345' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], [], []],
+ 'Invalid number' => ['FR', ['12345' => ['0711 / 25 24 28-90']], 200, null, null, []],
+ 'Invalid and valid number' => ['DE', ['12345' => ['NaN', '0711 / 25 24 28-90']], 200, ['+4971125242890'], [], []],
+ 'Valid and invalid number' => ['DE', ['12345' => ['0711 / 25 24 28-90', 'NaN']], 200, ['+4971125242890'], [], []],
+ 'Valid number and a match' => ['DE', ['12345' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], ['+4971125242890' => 'admin'], ['12345' => 'admin@localhost']],
+ 'Same number twice, later hits' => ['DE', ['12345' => ['0711 / 25 24 28-90'], '23456' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], ['+4971125242890' => 'admin'], ['23456' => 'admin@localhost']],
];
- $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['subadmin']));
}
- public function testEditUserRegularUserSelfEditChangeDisplayName() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSearchByPhoneNumbers')]
+ public function testSearchByPhoneNumbers(string $location, array $search, int $status, ?array $searchUsers, ?array $userMatches, array $expected): void {
+ $knownTo = 'knownTo';
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn($knownTo);
+ $this->userSession->method('getUser')
+ ->willReturn($user);
+
+ if ($searchUsers === null) {
+ $this->accountManager->expects($this->never())
+ ->method('searchUsers');
+ } else {
+ $this->accountManager->expects($this->once())
+ ->method('searchUsers')
+ ->with(IAccountManager::PROPERTY_PHONE, $searchUsers)
+ ->willReturn($userMatches);
+
+ $this->knownUserService->expects($this->once())
+ ->method('deleteKnownTo')
+ ->with($knownTo);
+
+ $this->knownUserService->expects($this->exactly(count($expected)))
+ ->method('storeIsKnownToUser')
+ ->with($knownTo, $this->anything());
+ }
+
+ $this->urlGenerator->method('getAbsoluteURL')
+ ->with('/')
+ ->willReturn('https://localhost/');
+
+ $response = $this->api->searchByPhoneNumbers($location, $search);
+
+ self::assertEquals($status, $response->getStatus());
+ self::assertEquals($expected, $response->getData());
+ }
+
+ public function testEditUserRegularUserSelfEditChangeDisplayName(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
+ $targetUser
+ ->expects($this->once())
+ ->method('getBackend')
+ ->willReturn($this->createMock(ISetDisplayNameBackend::class));
$targetUser
->expects($this->once())
->method('setDisplayName')
- ->with('NewDisplayName');
+ ->with('NewDisplayName')
+ ->willReturn(true);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->assertEquals([], $this->api->editUser('UserToEdit', 'display', 'NewDisplayName')->getData());
}
- public function testEditUserRegularUserSelfEditChangeEmailValid() {
+ public function testEditUserRegularUserSelfEditChangeEmailValid(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$targetUser
->expects($this->once())
- ->method('setEMailAddress')
- ->with('demo@owncloud.org');
+ ->method('setSystemEMailAddress')
+ ->with('demo@nextcloud.com');
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
- $this->assertEquals([], $this->api->editUser('UserToEdit', 'email', 'demo@owncloud.org')->getData());
+ $this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
+
+ $this->assertEquals([], $this->api->editUser('UserToEdit', 'email', 'demo@nextcloud.com')->getData());
}
+ public function testEditUserRegularUserSelfEditAddAdditionalEmailValid(): void {
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+ $targetUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->userManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('UserToEdit')
+ ->willReturn($targetUser);
+ $targetUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
+
+ $userAccount = $this->createMock(IAccount::class);
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- */
- public function testEditUserRegularUserSelfEditChangeEmailInvalid() {
+ $this->accountManager
+ ->expects($this->once())
+ ->method('getAccount')
+ ->with($targetUser)
+ ->willReturn($userAccount);
+ $this->accountManager
+ ->expects($this->once())
+ ->method('updateAccount')
+ ->with($userAccount);
+
+ $this->assertEquals([], $this->api->editUser('UserToEdit', 'additional_mail', 'demo1@nextcloud.com')->getData());
+ }
+
+ public function testEditUserRegularUserSelfEditAddAdditionalEmailMainAddress(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
+ $targetUser
+ ->expects($this->any())
+ ->method('getSystemEMailAddress')
+ ->willReturn('demo@nextcloud.com');
+
+ $userAccount = $this->createMock(IAccount::class);
+
+ $this->accountManager
+ ->expects($this->never())
+ ->method('getAccount')
+ ->with($targetUser)
+ ->willReturn($userAccount);
+ $this->accountManager
+ ->expects($this->never())
+ ->method('updateAccount')
+ ->with($userAccount);
+
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+ $this->api->editUser('UserToEdit', 'additional_mail', 'demo@nextcloud.com')->getData();
+ }
+
+ public function testEditUserRegularUserSelfEditAddAdditionalEmailDuplicate(): void {
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+ $targetUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->userManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('UserToEdit')
+ ->willReturn($targetUser);
+ $targetUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
+
+ $property = $this->createMock(IAccountProperty::class);
+ $property->method('getValue')
+ ->willReturn('demo1@nextcloud.com');
+ $collection = $this->createMock(IAccountPropertyCollection::class);
+ $collection->method('getPropertyByValue')
+ ->with('demo1@nextcloud.com')
+ ->willReturn($property);
+
+ $userAccount = $this->createMock(IAccount::class);
+ $userAccount->method('getPropertyCollection')
+ ->with(IAccountManager::COLLECTION_EMAIL)
+ ->willReturn($collection);
+
+ $this->accountManager
+ ->expects($this->once())
+ ->method('getAccount')
+ ->with($targetUser)
+ ->willReturn($userAccount);
+ $this->accountManager
+ ->expects($this->never())
+ ->method('updateAccount')
+ ->with($userAccount);
+
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+ $this->api->editUser('UserToEdit', 'additional_mail', 'demo1@nextcloud.com')->getData();
+ }
+
+ public function testEditUserRegularUserSelfEditChangeEmailInvalid(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+ $targetUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->userManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('UserToEdit')
+ ->willReturn($targetUser);
+ $targetUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
+
+ $this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
$this->api->editUser('UserToEdit', 'email', 'demo.org');
}
- public function testEditUserRegularUserSelfEditChangePassword() {
+ public static function selfEditChangePropertyProvider(): array {
+ return [
+ [IAccountManager::PROPERTY_TWITTER, '@oldtwitter', '@newtwitter'],
+ [IAccountManager::PROPERTY_BLUESKY, 'old.bluesky', 'new.bluesky'],
+ [IAccountManager::PROPERTY_FEDIVERSE, '@oldFediverse@floss.social', '@newFediverse@floss.social'],
+ [IAccountManager::PROPERTY_PHONE, '1234', '12345'],
+ [IAccountManager::PROPERTY_ADDRESS, 'Something street 2', 'Another street 3'],
+ [IAccountManager::PROPERTY_WEBSITE, 'https://examplesite1', 'https://examplesite2'],
+ [IAccountManager::PROPERTY_ORGANISATION, 'Organisation A', 'Organisation B'],
+ [IAccountManager::PROPERTY_ROLE, 'Human', 'Alien'],
+ [IAccountManager::PROPERTY_HEADLINE, 'Hi', 'Hello'],
+ [IAccountManager::PROPERTY_BIOGRAPHY, 'A biography', 'Another biography'],
+ [IAccountManager::PROPERTY_PROFILE_ENABLED, '1', '0'],
+ [IAccountManager::PROPERTY_PRONOUNS, 'they/them', 'he/him'],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('selfEditChangePropertyProvider')]
+ public function testEditUserRegularUserSelfEditChangeProperty($propertyName, $oldValue, $newValue): void {
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->userManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('UserToEdit')
+ ->willReturn($loggedInUser);
+
+ $backend = $this->createMock(UserInterface::class);
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
+
+ $propertyMock = $this->createMock(IAccountProperty::class);
+ $propertyMock->expects($this->any())
+ ->method('getName')
+ ->willReturn($propertyName);
+ $propertyMock->expects($this->any())
+ ->method('getValue')
+ ->willReturn($oldValue);
+ $propertyMock->expects($this->once())
+ ->method('setValue')
+ ->with($newValue)
+ ->willReturnSelf();
+ $propertyMock->expects($this->any())
+ ->method('getScope')
+ ->willReturn(IAccountManager::SCOPE_LOCAL);
+
+ $accountMock = $this->createMock(IAccount::class);
+ $accountMock->expects($this->any())
+ ->method('getProperty')
+ ->with($propertyName)
+ ->willReturn($propertyMock);
+
+ $this->accountManager->expects($this->atLeastOnce())
+ ->method('getAccount')
+ ->with($loggedInUser)
+ ->willReturn($accountMock);
+ $this->accountManager->expects($this->once())
+ ->method('updateAccount')
+ ->with($accountMock);
+
+ $this->assertEquals([], $this->api->editUser('UserToEdit', $propertyName, $newValue)->getData());
+ }
+
+ public function selfEditChangePropertyScopeProvider() {
+ return [
+ [IAccountManager::PROPERTY_AVATAR, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_DISPLAYNAME, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_EMAIL, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_TWITTER, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_BLUESKY, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_FEDIVERSE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_PHONE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_ADDRESS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_WEBSITE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_ORGANISATION, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_ROLE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_HEADLINE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_BIOGRAPHY, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_PROFILE_ENABLED, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ [IAccountManager::PROPERTY_PRONOUNS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('selfEditChangePropertyProvider')]
+ public function testEditUserRegularUserSelfEditChangePropertyScope($propertyName, $oldScope, $newScope): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+ $this->userSession
+ ->expects($this->once())
+ ->method('getUser')
+ ->willReturn($loggedInUser);
+ $this->userManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('UserToEdit')
+ ->willReturn($loggedInUser);
+
+ $backend = $this->createMock(UserInterface::class);
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
+
+ $propertyMock = $this->createMock(IAccountProperty::class);
+ $propertyMock->expects($this->any())
+ ->method('getName')
+ ->willReturn($propertyName);
+ $propertyMock->expects($this->any())
+ ->method('getValue')
+ ->willReturn('somevalue');
+ $propertyMock->expects($this->any())
+ ->method('getScope')
+ ->willReturn($oldScope);
+ $propertyMock->expects($this->atLeastOnce())
+ ->method('setScope')
+ ->with($newScope)
+ ->willReturnSelf();
+
+ $accountMock = $this->createMock(IAccount::class);
+ $accountMock->expects($this->any())
+ ->method('getProperty')
+ ->with($propertyName)
+ ->willReturn($propertyMock);
+
+ $this->accountManager->expects($this->atLeastOnce())
+ ->method('getAccount')
+ ->with($loggedInUser)
+ ->willReturn($accountMock);
+ $this->accountManager->expects($this->once())
+ ->method('updateAccount')
+ ->with($accountMock);
+
+ $this->assertEquals([], $this->api->editUser('UserToEdit', $propertyName . 'Scope', $newScope)->getData());
+ }
+
+ public function testEditUserRegularUserSelfEditChangePassword(): void {
+ $loggedInUser = $this->getMockBuilder(IUser::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggedInUser
+ ->expects($this->any())
+ ->method('getUID')
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
+ $targetUser
+ ->expects($this->once())
+ ->method('canChangePassword')
+ ->willReturn(true);
$targetUser
->expects($this->once())
->method('setPassword')
@@ -1091,50 +2079,71 @@ class UsersControllerTest extends TestCase {
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'password', 'NewPassword')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testEditUserRegularUserSelfEditChangeQuota() {
+
+ public function testEditUserRegularUserSelfEditChangeQuota(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(113);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->api->editUser('UserToEdit', 'quota', 'NewQuota');
}
- public function testEditUserAdminUserSelfEditChangeValidQuota() {
+ public function testEditUserAdminUserSelfEditChangeValidQuota(): void {
+ $this->config
+ ->expects($this->once())
+ ->method('getAppValue')
+ ->willReturnCallback(function ($appid, $key, $default) {
+ if ($key === 'max_quota') {
+ return '-1';
+ }
+ return null;
+ });
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser->expects($this->once())
->method('setQuota')
@@ -1142,66 +2151,87 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('isAdmin')
->with('UID')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 103
- * @expectedExceptionMessage Invalid quota value ABC
- */
- public function testEditUserAdminUserSelfEditChangeInvalidQuota() {
+
+ public function testEditUserAdminUserSelfEditChangeInvalidQuota(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Invalid quota value: ABC');
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('isAdmin')
->with('UID')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->api->editUser('UserToEdit', 'quota', 'ABC');
}
- public function testEditUserAdminUserEditChangeValidQuota() {
+ public function testEditUserAdminUserEditChangeValidQuota(): void {
+ $this->config
+ ->expects($this->once())
+ ->method('getAppValue')
+ ->willReturnCallback(function ($appid, $key, $default) {
+ if ($key === 'max_quota') {
+ return '-1';
+ }
+ return null;
+ });
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser->expects($this->once())
->method('setQuota')
@@ -1209,34 +2239,39 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
}
- public function testEditUserSelfEditChangeLanguage() {
-
+ public function testEditUserSelfEditChangeLanguage(): void {
$this->l10nFactory->expects($this->once())
->method('findAvailableLanguages')
->willReturn(['en', 'de', 'sv']);
@@ -1251,7 +2286,7 @@ class UsersControllerTest extends TestCase {
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
$targetUser = $this->createMock(IUser::class);
$this->config->expects($this->once())
->method('setUserValue')
@@ -1259,37 +2294,42 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->atLeastOnce())
->method('isAdmin')
->with('UserToEdit')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
}
- public function dataEditUserSelfEditChangeLanguageButForced() {
+ public static function dataEditUserSelfEditChangeLanguageButForced(): array {
return [
['de'],
[true],
];
}
- /**
- * @dataProvider dataEditUserSelfEditChangeLanguageButForced
- * @expectedException \OCP\AppFramework\OCS\OCSException
- */
- public function testEditUserSelfEditChangeLanguageButForced($forced) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataEditUserSelfEditChangeLanguageButForced')]
+ public function testEditUserSelfEditChangeLanguageButForced($forced): void {
+ $this->expectException(OCSException::class);
+
$this->config->expects($this->any())
->method('getSystemValue')
->willReturnMap([
@@ -1301,34 +2341,39 @@ class UsersControllerTest extends TestCase {
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
$targetUser = $this->createMock(IUser::class);
$this->config->expects($this->never())
->method('setUserValue');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->atLeastOnce())
->method('isAdmin')
->with('UserToEdit')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
}
- public function testEditUserAdminEditChangeLanguage() {
-
+ public function testEditUserAdminEditChangeLanguage(): void {
$this->l10nFactory->expects($this->once())
->method('findAvailableLanguages')
->willReturn(['en', 'de', 'sv']);
@@ -1337,7 +2382,7 @@ class UsersControllerTest extends TestCase {
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->createMock(IUser::class);
$this->config->expects($this->once())
->method('setUserValue')
@@ -1345,35 +2390,40 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$subAdminManager = $this->createMock(SubAdmin::class);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
}
- /**
- * @dataProvider dataEditUserSelfEditChangeLanguageButForced
- * @expectedException \OCP\AppFramework\OCS\OCSException
- */
- public function testEditUserAdminEditChangeLanguageInvalidLanguage() {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataEditUserSelfEditChangeLanguageButForced')]
+ public function testEditUserAdminEditChangeLanguageInvalidLanguage(): void {
+ $this->expectException(OCSException::class);
+
$this->l10nFactory->expects($this->once())
->method('findAvailableLanguages')
@@ -1383,43 +2433,58 @@ class UsersControllerTest extends TestCase {
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->createMock(IUser::class);
$this->config->expects($this->never())
->method('setUserValue');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$subAdminManager = $this->createMock(SubAdmin::class);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'ru')->getData());
}
- public function testEditUserSubadminUserAccessible() {
+ public function testEditUserSubadminUserAccessible(): void {
+ $this->config
+ ->expects($this->once())
+ ->method('getAppValue')
+ ->willReturnCallback(function ($appid, $key, $default) {
+ if ($key === 'max_quota') {
+ return '-1';
+ }
+ return null;
+ });
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser->expects($this->once())
->method('setQuota')
@@ -1427,12 +2492,12 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -1440,39 +2505,45 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
+
+ $backend = $this->createMock(UserInterface::class);
+ $targetUser
+ ->expects($this->any())
+ ->method('getBackend')
+ ->willReturn($backend);
$this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testEditUserSubadminUserInaccessible() {
+
+ public function testEditUserSubadminUserInaccessible(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToEdit')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -1480,467 +2551,467 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->api->editUser('UserToEdit', 'quota', 'value');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testDeleteUserNotExistingUser() {
+
+ public function testDeleteUserNotExistingUser(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UserToEdit'));
+ ->willReturn('UserToEdit');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->deleteUser('UserToDelete');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testDeleteUserSelf() {
+
+ public function testDeleteUserSelf(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->api->deleteUser('UserToDelete');
}
- public function testDeleteSuccessfulUserAsAdmin() {
+ public function testDeleteSuccessfulUserAsAdmin(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$targetUser
->expects($this->once())
->method('delete')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->assertEquals([], $this->api->deleteUser('UserToDelete')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testDeleteUnsuccessfulUserAsAdmin() {
+
+ public function testDeleteUnsuccessfulUserAsAdmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$targetUser
->expects($this->once())
->method('delete')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->api->deleteUser('UserToDelete');
}
- public function testDeleteSuccessfulUserAsSubadmin() {
+ public function testDeleteSuccessfulUserAsSubadmin(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->once())
->method('delete')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->assertEquals([], $this->api->deleteUser('UserToDelete')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testDeleteUnsuccessfulUserAsSubadmin() {
+
+ public function testDeleteUnsuccessfulUserAsSubadmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->once())
->method('delete')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->api->deleteUser('UserToDelete');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testDeleteUserAsSubAdminAndUserIsNotAccessible() {
+
+ public function testDeleteUserAsSubAdminAndUserIsNotAccessible(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UID'));
+ ->willReturn('UID');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToDelete')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->api->deleteUser('UserToDelete');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 998
- */
- public function testGetUsersGroupsTargetUserNotExisting() {
+
+ public function testGetUsersGroupsTargetUserNotExisting(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->api->getUsersGroups('UserToLookup');
}
- public function testGetUsersGroupsSelfTargetted() {
+ public function testGetUsersGroupsSelfTargetted(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(3))
->method('getUID')
- ->will($this->returnValue('UserToLookup'));
+ ->willReturn('UserToLookup');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UserToLookup'));
+ ->willReturn('UserToLookup');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToLookup')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('getUserGroupIds')
->with($targetUser)
- ->will($this->returnValue(['DummyValue']));
+ ->willReturn(['DummyValue']);
$this->assertEquals(['groups' => ['DummyValue']], $this->api->getUsersGroups('UserToLookup')->getData());
}
- public function testGetUsersGroupsForAdminUser() {
+ public function testGetUsersGroupsForAdminUser(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UserToLookup'));
+ ->willReturn('UserToLookup');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToLookup')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('getUserGroupIds')
->with($targetUser)
- ->will($this->returnValue(['DummyValue']));
+ ->willReturn(['DummyValue']);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->assertEquals(['groups' => ['DummyValue']], $this->api->getUsersGroups('UserToLookup')->getData());
}
- public function testGetUsersGroupsForSubAdminUserAndUserIsAccessible() {
+ public function testGetUsersGroupsForSubAdminUserAndUserIsAccessible(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UserToLookup'));
+ ->willReturn('UserToLookup');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToLookup')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$group1 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$group1
->expects($this->any())
->method('getGID')
- ->will($this->returnValue('Group1'));
+ ->willReturn('Group1');
$group2 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$group2
->expects($this->any())
->method('getGID')
- ->will($this->returnValue('Group2'));
+ ->willReturn('Group2');
$subAdminManager
->expects($this->once())
->method('getSubAdminsGroups')
->with($loggedInUser)
- ->will($this->returnValue([$group1, $group2]));
+ ->willReturn([$group1, $group2]);
$this->groupManager
->expects($this->any())
->method('getUserGroupIds')
->with($targetUser)
- ->will($this->returnValue(['Group1']));
+ ->willReturn(['Group1']);
$this->assertEquals(['groups' => ['Group1']], $this->api->getUsersGroups('UserToLookup')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testGetUsersGroupsForSubAdminUserAndUserIsInaccessible() {
+
+ public function testGetUsersGroupsForSubAdminUserAndUserIsInaccessible(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('UserToLookup'));
+ ->willReturn('UserToLookup');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToLookup')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->any())
->method('getUserGroupIds')
->with($targetUser)
- ->will($this->returnValue(['Group1']));
+ ->willReturn(['Group1']);
$this->api->getUsersGroups('UserToLookup');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- */
- public function testAddToGroupWithTargetGroupNotExisting() {
+
+ public function testAddToGroupWithTargetGroupNotExisting(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(102);
+
$this->groupManager->expects($this->once())
->method('get')
->with('GroupToAddTo')
@@ -1949,19 +3020,19 @@ class UsersControllerTest extends TestCase {
$this->api->addToGroup('TargetUser', 'GroupToAddTo');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testAddToGroupWithNoGroupSpecified() {
+
+ public function testAddToGroupWithNoGroupSpecified(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$this->api->addToGroup('TargetUser');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 103
- */
- public function testAddToGroupWithTargetUserNotExisting() {
+
+ public function testAddToGroupWithTargetUserNotExisting(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(103);
+
$targetGroup = $this->createMock(IGroup::class);
$this->groupManager->expects($this->once())
->method('get')
@@ -1971,14 +3042,14 @@ class UsersControllerTest extends TestCase {
$this->api->addToGroup('TargetUser', 'GroupToAddTo');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 104
- */
- public function testAddToGroupNoSubadmin() {
+
+ public function testAddToGroupNoSubadmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(104);
+
$targetUser = $this->createMock(IUser::class);
$loggedInUser = $this->createMock(IUser::class);
- $loggedInUser->expects($this->once())
+ $loggedInUser->expects($this->exactly(2))
->method('getUID')
->willReturn('subadmin');
@@ -2019,10 +3090,10 @@ class UsersControllerTest extends TestCase {
$this->api->addToGroup('TargetUser', 'GroupToAddTo');
}
- public function testAddToGroupSuccessAsSubadmin() {
+ public function testAddToGroupSuccessAsSubadmin(): void {
$targetUser = $this->createMock(IUser::class);
$loggedInUser = $this->createMock(IUser::class);
- $loggedInUser->expects($this->once())
+ $loggedInUser->expects($this->exactly(2))
->method('getUID')
->willReturn('subadmin');
@@ -2063,10 +3134,10 @@ class UsersControllerTest extends TestCase {
$this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo'));
}
- public function testAddToGroupSuccessAsAdmin() {
+ public function testAddToGroupSuccessAsAdmin(): void {
$targetUser = $this->createMock(IUser::class);
$loggedInUser = $this->createMock(IUser::class);
- $loggedInUser->expects($this->once())
+ $loggedInUser->expects($this->exactly(2))
->method('getUID')
->willReturn('admin');
@@ -2105,277 +3176,277 @@ class UsersControllerTest extends TestCase {
$this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo'));
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testRemoveFromGroupWithNoTargetGroup() {
+
+ public function testRemoveFromGroupWithNoTargetGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
- $this->api->removeFromGroup('TargetUser', null);
+ $this->api->removeFromGroup('TargetUser', '');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- */
- public function testRemoveFromGroupWithEmptyTargetGroup() {
+
+ public function testRemoveFromGroupWithEmptyTargetGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->api->removeFromGroup('TargetUser', '');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- */
- public function testRemoveFromGroupWithNotExistingTargetGroup() {
+
+ public function testRemoveFromGroupWithNotExistingTargetGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(102);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('TargetGroup')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->removeFromGroup('TargetUser', 'TargetGroup');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 103
- */
- public function testRemoveFromGroupWithNotExistingTargetUser() {
+
+ public function testRemoveFromGroupWithNotExistingTargetUser(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(103);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('TargetGroup')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->userManager
->expects($this->once())
->method('get')
->with('TargetUser')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->removeFromGroup('TargetUser', 'TargetGroup');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 104
- */
- public function testRemoveFromGroupWithoutPermission() {
+
+ public function testRemoveFromGroupWithoutPermission(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(104);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->once())
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('unauthorizedUser'));
+ ->willReturn('unauthorizedUser');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('TargetGroup')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->userManager
->expects($this->once())
->method('get')
->with('TargetUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('unauthorizedUser')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->api->removeFromGroup('TargetUser', 'TargetGroup');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 105
- * @expectedExceptionMessage Cannot remove yourself from the admin group
- */
- public function testRemoveFromGroupAsAdminFromAdmin() {
+
+ public function testRemoveFromGroupAsAdminFromAdmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Cannot remove yourself from the admin group');
+ $this->expectExceptionCode(105);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$targetGroup
->expects($this->once())
->method('getGID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('admin')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->userManager
->expects($this->once())
->method('get')
->with('Admin')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->any())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->api->removeFromGroup('Admin', 'admin');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 105
- * @expectedExceptionMessage Cannot remove yourself from this group as you are a SubAdmin
- */
- public function testRemoveFromGroupAsSubAdminFromSubAdmin() {
+
+ public function testRemoveFromGroupAsSubAdminFromSubAdmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Cannot remove yourself from this group as you are a sub-admin');
+ $this->expectExceptionCode(105);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser
->expects($this->once())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$targetGroup
->expects($this->any())
->method('getGID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('subadmin')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->userManager
->expects($this->once())
->method('get')
->with('SubAdmin')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
- ->method('isSubAdminofGroup')
+ ->method('isSubAdminOfGroup')
->with($loggedInUser, $targetGroup)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->any())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->api->removeFromGroup('SubAdmin', 'subadmin');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 105
- * @expectedExceptionMessage Cannot remove user from this group as this is the only remaining group you are a SubAdmin of
- */
- public function testRemoveFromGroupAsSubAdminFromLastSubAdminGroup() {
+
+ public function testRemoveFromGroupAsSubAdminFromLastSubAdminGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Not viable to remove user from the last group you are sub-admin of');
+ $this->expectExceptionCode(105);
+
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$targetGroup
->expects($this->any())
->method('getGID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('subadmin')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->userManager
->expects($this->once())
->method('get')
->with('AnotherUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
- ->method('isSubAdminofGroup')
+ ->method('isSubAdminOfGroup')
->with($loggedInUser, $targetGroup)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$subAdminManager
->expects($this->once())
->method('getSubAdminsGroups')
->with($loggedInUser)
- ->will($this->returnValue([$targetGroup]));
+ ->willReturn([$targetGroup]);
$this->groupManager
->expects($this->any())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getUserGroupIds')
@@ -2385,39 +3456,39 @@ class UsersControllerTest extends TestCase {
$this->api->removeFromGroup('AnotherUser', 'subadmin');
}
- public function testRemoveFromGroupSuccessful() {
+ public function testRemoveFromGroupSuccessful(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
->expects($this->any())
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('admin')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->userManager
->expects($this->once())
->method('get')
->with('AnotherUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->groupManager
->expects($this->any())
->method('isAdmin')
->with('admin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$targetGroup
->expects($this->once())
->method('removeUser')
@@ -2426,379 +3497,274 @@ class UsersControllerTest extends TestCase {
$this->assertEquals([], $this->api->removeFromGroup('AnotherUser', 'admin')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage User does not exist
- */
- public function testAddSubAdminWithNotExistingTargetUser() {
+
+ public function testAddSubAdminWithNotExistingTargetUser(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('User does not exist');
+ $this->expectExceptionCode(101);
+
$this->userManager
->expects($this->once())
->method('get')
->with('NotExistingUser')
- ->will($this->returnValue(null));
+ ->willReturn(null);
- $this->api->addSubAdmin('NotExistingUser', null);
+ $this->api->addSubAdmin('NotExistingUser', '');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- * @expectedExceptionMessage Group does not exist
- */
- public function testAddSubAdminWithNotExistingTargetGroup() {
+
+ public function testAddSubAdminWithNotExistingTargetGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Group does not exist');
+ $this->expectExceptionCode(102);
+
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('NotExistingGroup')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->addSubAdmin('ExistingUser', 'NotExistingGroup');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 103
- * @expectedExceptionMessage Cannot create subadmins for admin group
- */
- public function testAddSubAdminToAdminGroup() {
+
+ public function testAddSubAdminToAdminGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Cannot create sub-admins for admin group');
+ $this->expectExceptionCode(103);
+
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$targetGroup
->expects($this->once())
->method('getGID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('ADmiN')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$this->api->addSubAdmin('ExistingUser', 'ADmiN');
}
- public function testAddSubAdminTwice() {
+ public function testAddSubAdminTwice(): void {
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('TargetGroup')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isSubAdminOfGroup')
->with($targetUser, $targetGroup)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->assertEquals([], $this->api->addSubAdmin('ExistingUser', 'TargetGroup')->getData());
}
- public function testAddSubAdminSuccessful() {
+ public function testAddSubAdminSuccessful(): void {
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('TargetGroup')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isSubAdminOfGroup')
->with($targetUser, $targetGroup)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager
->expects($this->once())
->method('createSubAdmin')
- ->with($targetUser, $targetGroup)
- ->will($this->returnValue(true));
+ ->with($targetUser, $targetGroup);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->assertEquals([], $this->api->addSubAdmin('ExistingUser', 'TargetGroup')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 103
- * @expectedExceptionMessage Unknown error occurred
- */
- public function testAddSubAdminUnsuccessful() {
- $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
- $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
- $this->userManager
- ->expects($this->once())
- ->method('get')
- ->with('ExistingUser')
- ->will($this->returnValue($targetUser));
- $this->groupManager
- ->expects($this->once())
- ->method('get')
- ->with('TargetGroup')
- ->will($this->returnValue($targetGroup));
- $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
- ->disableOriginalConstructor()->getMock();
- $subAdminManager
- ->expects($this->once())
- ->method('isSubAdminOfGroup')
- ->with($targetUser, $targetGroup)
- ->will($this->returnValue(false));
- $subAdminManager
- ->expects($this->once())
- ->method('createSubAdmin')
- ->with($targetUser, $targetGroup)
- ->will($this->returnValue(false));
- $this->groupManager
- ->expects($this->once())
- ->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
- $this->api->addSubAdmin('ExistingUser', 'TargetGroup');
- }
+ public function testRemoveSubAdminNotExistingTargetUser(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('User does not exist');
+ $this->expectExceptionCode(101);
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage User does not exist
- */
- public function testRemoveSubAdminNotExistingTargetUser() {
$this->userManager
->expects($this->once())
->method('get')
->with('NotExistingUser')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->removeSubAdmin('NotExistingUser', 'GroupToDeleteFrom');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage Group does not exist
- */
- public function testRemoveSubAdminNotExistingTargetGroup() {
+
+ public function testRemoveSubAdminNotExistingTargetGroup(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Group does not exist');
+ $this->expectExceptionCode(101);
+
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('GroupToDeleteFrom')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- * @expectedExceptionMessage User is not a subadmin of this group
- */
- public function testRemoveSubAdminFromNotASubadmin() {
+
+ public function testRemoveSubAdminFromNotASubadmin(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('User is not a sub-admin of this group');
+ $this->expectExceptionCode(102);
+
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('GroupToDeleteFrom')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isSubAdminOfGroup')
->with($targetUser, $targetGroup)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
}
- public function testRemoveSubAdminSuccessful() {
+ public function testRemoveSubAdminSuccessful(): void {
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$this->userManager
->expects($this->once())
->method('get')
->with('ExistingUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('get')
->with('GroupToDeleteFrom')
- ->will($this->returnValue($targetGroup));
+ ->willReturn($targetGroup);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('isSubAdminOfGroup')
->with($targetUser, $targetGroup)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$subAdminManager
->expects($this->once())
->method('deleteSubAdmin')
- ->with($targetUser, $targetGroup)
- ->will($this->returnValue(true));
+ ->with($targetUser, $targetGroup);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->assertEquals([], $this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 103
- * @expectedExceptionMessage Unknown error occurred
- */
- public function testRemoveSubAdminUnsuccessful() {
- $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
- $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
- $this->userManager
- ->expects($this->once())
- ->method('get')
- ->with('ExistingUser')
- ->will($this->returnValue($targetUser));
- $this->groupManager
- ->expects($this->once())
- ->method('get')
- ->with('GroupToDeleteFrom')
- ->will($this->returnValue($targetGroup));
- $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
- ->disableOriginalConstructor()->getMock();
- $subAdminManager
- ->expects($this->once())
- ->method('isSubAdminOfGroup')
- ->with($targetUser, $targetGroup)
- ->will($this->returnValue(true));
- $subAdminManager
- ->expects($this->once())
- ->method('deleteSubAdmin')
- ->with($targetUser, $targetGroup)
- ->will($this->returnValue(false));
- $this->groupManager
- ->expects($this->once())
- ->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
- $this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
- }
+ public function testGetUserSubAdminGroupsNotExistingTargetUser(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('User does not exist');
+ $this->expectExceptionCode(404);
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage User does not exist
- */
- public function testGetUserSubAdminGroupsNotExistingTargetUser() {
$this->userManager
->expects($this->once())
->method('get')
->with('RequestedUser')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->getUserSubAdminGroups('RequestedUser');
}
- public function testGetUserSubAdminGroupsWithGroups() {
+ public function testGetUserSubAdminGroupsWithGroups(): void {
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
$targetGroup
->expects($this->once())
->method('getGID')
- ->will($this->returnValue('TargetGroup'));
+ ->willReturn('TargetGroup');
$this->userManager
->expects($this->once())
->method('get')
->with('RequestedUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()->getMock();
$subAdminManager
->expects($this->once())
->method('getSubAdminsGroups')
->with($targetUser)
- ->will($this->returnValue([$targetGroup]));
+ ->willReturn([$targetGroup]);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->assertEquals(['TargetGroup'], $this->api->getUserSubAdminGroups('RequestedUser')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- * @expectedExceptionMessage Unknown error occurred
- */
- public function testGetUserSubAdminGroupsWithoutGroups() {
- $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
- $this->userManager
- ->expects($this->once())
- ->method('get')
- ->with('RequestedUser')
- ->will($this->returnValue($targetUser));
- $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
- ->disableOriginalConstructor()->getMock();
- $subAdminManager
- ->expects($this->once())
- ->method('getSubAdminsGroups')
- ->with($targetUser)
- ->will($this->returnValue([]));
- $this->groupManager
- ->expects($this->once())
- ->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
-
- $this->api->getUserSubAdminGroups('RequestedUser');
- }
-
- public function testEnableUser() {
+ public function testEnableUser(): void {
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser->expects($this->once())
->method('setEnabled')
@@ -2807,25 +3773,25 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('get')
->with('RequestedUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->assertEquals([], $this->api->enableUser('RequestedUser')->getData());
}
- public function testDisableUser() {
+ public function testDisableUser(): void {
$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$targetUser->expects($this->once())
->method('setEnabled')
@@ -2834,61 +3800,78 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('get')
->with('RequestedUser')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$loggedInUser
- ->expects($this->exactly(2))
+ ->expects($this->exactly(3))
->method('getUID')
- ->will($this->returnValue('admin'));
+ ->willReturn('admin');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->assertEquals([], $this->api->disableUser('RequestedUser')->getData());
}
- public function testGetCurrentUserLoggedIn() {
+ public function testGetCurrentUserLoggedIn(): void {
$user = $this->createMock(IUser::class);
$user->expects($this->once())->method('getUID')->willReturn('UID');
$this->userSession->expects($this->once())->method('getUser')
->willReturn($user);
- /** @var UsersController | PHPUnit_Framework_MockObject_MockObject $api */
- $api = $this->getMockBuilder('OCA\Provisioning_API\Controller\UsersController')
+ /** @var UsersController | MockObject $api */
+ $api = $this->getMockBuilder(UsersController::class)
->setConstructorArgs([
'provisioning_api',
$this->request,
$this->userManager,
$this->config,
- $this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
- $this->logger,
+ $this->subAdminManager,
$this->l10nFactory,
- $this->newUserMailHelper
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->logger,
+ $this->newUserMailHelper,
+ $this->secureRandom,
+ $this->remoteWipe,
+ $this->knownUserService,
+ $this->eventDispatcher,
+ $this->phoneNumberUtil,
+ $this->appManager,
])
- ->setMethods(['getUserData'])
+ ->onlyMethods(['getUserData'])
->getMock();
- $api->expects($this->once())->method('getUserData')->with('UID')
+ $api->expects($this->once())->method('getUserData')->with('UID', true)
->willReturn(
[
'id' => 'UID',
'enabled' => 'true',
'quota' => ['DummyValue'],
- 'email' => 'demo@owncloud.org',
+ 'email' => 'demo@nextcloud.com',
'displayname' => 'Demo User',
+ 'display-name' => 'Demo User',
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
- 'twitter' => 'twitter'
+ 'twitter' => 'twitter',
+ 'bluesky' => 'bluesky',
+ 'fediverse' => 'fediverse',
+ 'organisation' => 'organisation',
+ 'role' => 'role',
+ 'headline' => 'headline',
+ 'biography' => 'biography',
+ 'profile_enabled' => '1',
+ 'pronouns' => 'they/them',
]
);
@@ -2896,21 +3879,30 @@ class UsersControllerTest extends TestCase {
'id' => 'UID',
'enabled' => 'true',
'quota' => ['DummyValue'],
- 'email' => 'demo@owncloud.org',
+ 'email' => 'demo@nextcloud.com',
+ 'displayname' => 'Demo User',
+ 'display-name' => 'Demo User',
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
- 'display-name' => 'Demo User'
+ 'bluesky' => 'bluesky',
+ 'fediverse' => 'fediverse',
+ 'organisation' => 'organisation',
+ 'role' => 'role',
+ 'headline' => 'headline',
+ 'biography' => 'biography',
+ 'profile_enabled' => '1',
+ 'pronouns' => 'they/them',
];
$this->assertSame($expected, $api->getCurrentUser()->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- */
- public function testGetCurrentUserNotLoggedIn() {
+
+ public function testGetCurrentUserNotLoggedIn(): void {
+ $this->expectException(OCSException::class);
+
$this->userSession->expects($this->once())->method('getUser')
->willReturn(null);
@@ -2918,88 +3910,117 @@ class UsersControllerTest extends TestCase {
$this->api->getCurrentUser();
}
+ public function testGetUser(): void {
+ $loggedInUser = $this->createMock(IUser::class);
+ $loggedInUser
+ ->method('getUID')
+ ->willReturn('currentuser');
+ $this->userSession
+ ->method('getUser')
+ ->willReturn($loggedInUser);
- public function testGetUser() {
- /** @var UsersController | PHPUnit_Framework_MockObject_MockObject $api */
- $api = $this->getMockBuilder('OCA\Provisioning_API\Controller\UsersController')
+ /** @var UsersController | MockObject $api */
+ $api = $this->getMockBuilder(UsersController::class)
->setConstructorArgs([
'provisioning_api',
$this->request,
$this->userManager,
$this->config,
- $this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
- $this->logger,
+ $this->subAdminManager,
$this->l10nFactory,
- $this->newUserMailHelper
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->logger,
+ $this->newUserMailHelper,
+ $this->secureRandom,
+ $this->remoteWipe,
+ $this->knownUserService,
+ $this->eventDispatcher,
+ $this->phoneNumberUtil,
+ $this->appManager,
])
- ->setMethods(['getUserData'])
+ ->onlyMethods(['getUserData'])
->getMock();
$expected = [
'id' => 'UID',
'enabled' => 'true',
'quota' => ['DummyValue'],
- 'email' => 'demo@owncloud.org',
+ 'email' => 'demo@nextcloud.com',
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
- 'displayname' => 'Demo User'
+ 'bluesky' => 'bluesky',
+ 'fediverse' => 'fediverse',
+ 'displayname' => 'Demo User',
+ 'display-name' => 'Demo User',
+ 'organisation' => 'organisation',
+ 'role' => 'role',
+ 'headline' => 'headline',
+ 'biography' => 'biography',
+ 'profile_enabled' => '1',
+ 'pronouns' => 'they/them',
];
- $api->expects($this->once())->method('getUserData')
- ->with('uid')
- ->willReturn($expected);
+ $api->expects($this->exactly(2))
+ ->method('getUserData')
+ ->willReturnMap([
+ ['uid', false, $expected],
+ ['currentuser', true, $expected],
+ ]);
$this->assertSame($expected, $api->getUser('uid')->getData());
+
+ $this->assertSame($expected, $api->getUser('currentuser')->getData());
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 998
- */
- public function testResendWelcomeMessageWithNotExistingTargetUser() {
+
+ public function testResendWelcomeMessageWithNotExistingTargetUser(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$this->userManager
->expects($this->once())
->method('get')
->with('NotExistingUser')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->resendWelcomeMessage('NotExistingUser');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 997
- */
- public function testResendWelcomeMessageAsSubAdminAndUserIsNotAccessible() {
+
+ public function testResendWelcomeMessageAsSubAdminAndUserIsNotAccessible(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionCode(998);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$loggedInUser
- ->expects($this->exactly(1))
+ ->expects($this->exactly(2))
->method('getUID')
- ->will($this->returnValue('subadmin'));
+ ->willReturn('subadmin');
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$this->groupManager
->expects($this->once())
->method('isAdmin')
->with('subadmin')
- ->will($this->returnValue(false));
+ ->willReturn(false);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -3007,21 +4028,21 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(false));
+ ->willReturn(false);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$this->api->resendWelcomeMessage('UserToGet');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage Email address not available
- */
- public function testResendWelcomeMessageNoEmail() {
+
+ public function testResendWelcomeMessageNoEmail(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Email address not available');
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
@@ -3031,12 +4052,12 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -3044,25 +4065,29 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
+ $loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('logged-user-id');
$targetUser
->expects($this->once())
->method('getEmailAddress')
- ->will($this->returnValue(''));
+ ->willReturn('');
$this->api->resendWelcomeMessage('UserToGet');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 101
- * @expectedExceptionMessage Email address not available
- */
- public function testResendWelcomeMessageNullEmail() {
+
+ public function testResendWelcomeMessageNullEmail(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Email address not available');
+ $this->expectExceptionCode(101);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
@@ -3072,12 +4097,12 @@ class UsersControllerTest extends TestCase {
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -3085,38 +4110,45 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
+ $loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('logged-user-id');
$targetUser
->expects($this->once())
->method('getEmailAddress')
- ->will($this->returnValue(null));
+ ->willReturn(null);
$this->api->resendWelcomeMessage('UserToGet');
}
- public function testResendWelcomeMessageSuccess() {
+ public function testResendWelcomeMessageSuccess(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
+ $loggedInUser
+ ->method('getUID')
+ ->willReturn('logged-user-id');
$targetUser
->method('getUID')
->willReturn('user-id');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -3124,69 +4156,50 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->once())
->method('getEmailAddress')
- ->will($this->returnValue('abc@example.org'));
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('user-id', 'core', 'lang')
- ->willReturn('es');
- $l10n = $this->getMockBuilder(IL10N::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->l10nFactory
- ->expects($this->at(0))
- ->method('languageExists')
- ->with('settings', 'es')
- ->willReturn(true);
- $this->l10nFactory
- ->expects($this->at(1))
- ->method('get')
- ->with('settings', 'es')
- ->willReturn($l10n);
+ ->willReturn('abc@example.org');
$emailTemplate = $this->createMock(IEMailTemplate::class);
$this->newUserMailHelper
- ->expects($this->at(0))
- ->method('setL10N')
- ->willReturn($l10n);
- $this->newUserMailHelper
- ->expects($this->at(1))
+ ->expects($this->once())
->method('generateTemplate')
->willReturn($emailTemplate);
$this->newUserMailHelper
- ->expects($this->at(2))
+ ->expects($this->once())
->method('sendMail')
->with($targetUser, $emailTemplate);
$this->api->resendWelcomeMessage('UserToGet');
}
- public function testResendWelcomeMessageSuccessWithFallbackLanguage() {
+ public function testResendWelcomeMessageSuccessWithFallbackLanguage(): void {
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
+ $loggedInUser
+ ->method('getUID')
+ ->willReturn('logged-user-id');
$targetUser
->method('getUID')
->willReturn('user-id');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -3194,74 +4207,56 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->once())
->method('getEmailAddress')
- ->will($this->returnValue('abc@example.org'));
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('user-id', 'core', 'lang')
- ->willReturn('es');
- $l10n = $this->getMockBuilder(IL10N::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->l10nFactory
- ->expects($this->at(0))
- ->method('languageExists')
- ->with('settings', 'es')
- ->willReturn(false);
- $this->l10nFactory
- ->expects($this->at(1))
- ->method('get')
- ->with('settings', 'en')
- ->willReturn($l10n);
+ ->willReturn('abc@example.org');
$emailTemplate = $this->createMock(IEMailTemplate::class);
$this->newUserMailHelper
- ->expects($this->at(0))
- ->method('setL10N')
- ->willReturn($l10n);
- $this->newUserMailHelper
- ->expects($this->at(1))
+ ->expects($this->once())
->method('generateTemplate')
->willReturn($emailTemplate);
$this->newUserMailHelper
- ->expects($this->at(2))
+ ->expects($this->once())
->method('sendMail')
->with($targetUser, $emailTemplate);
$this->api->resendWelcomeMessage('UserToGet');
}
- /**
- * @expectedException \OCP\AppFramework\OCS\OCSException
- * @expectedExceptionCode 102
- * @expectedExceptionMessage Sending email failed
- */
- public function testResendWelcomeMessageFailed() {
+
+ public function testResendWelcomeMessageFailed(): void {
+ $this->expectException(OCSException::class);
+ $this->expectExceptionMessage('Sending email failed');
+ $this->expectExceptionCode(102);
+
$loggedInUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
$targetUser = $this->getMockBuilder(IUser::class)
->disableOriginalConstructor()
->getMock();
+ $loggedInUser
+ ->expects($this->exactly(2))
+ ->method('getUID')
+ ->willReturn('logged-user-id');
$targetUser
->method('getUID')
->willReturn('user-id');
$this->userSession
->expects($this->once())
->method('getUser')
- ->will($this->returnValue($loggedInUser));
+ ->willReturn($loggedInUser);
$this->userManager
->expects($this->once())
->method('get')
->with('UserToGet')
- ->will($this->returnValue($targetUser));
+ ->willReturn($targetUser);
$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
->disableOriginalConstructor()
->getMock();
@@ -3269,48 +4264,200 @@ class UsersControllerTest extends TestCase {
->expects($this->once())
->method('isUserAccessible')
->with($loggedInUser, $targetUser)
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->groupManager
->expects($this->once())
->method('getSubAdmin')
- ->will($this->returnValue($subAdminManager));
+ ->willReturn($subAdminManager);
$targetUser
->expects($this->once())
->method('getEmailAddress')
- ->will($this->returnValue('abc@example.org'));
- $this->config
- ->expects($this->at(0))
- ->method('getUserValue')
- ->with('user-id', 'core', 'lang')
- ->willReturn('es');
- $l10n = $this->getMockBuilder(IL10N::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->l10nFactory
- ->expects($this->at(0))
- ->method('languageExists')
- ->with('settings', 'es')
- ->willReturn(true);
- $this->l10nFactory
- ->expects($this->at(1))
- ->method('get')
- ->with('settings', 'es')
- ->willReturn($l10n);
+ ->willReturn('abc@example.org');
$emailTemplate = $this->createMock(IEMailTemplate::class);
$this->newUserMailHelper
- ->expects($this->at(0))
- ->method('setL10N')
- ->willReturn($l10n);
- $this->newUserMailHelper
- ->expects($this->at(1))
+ ->expects($this->once())
->method('generateTemplate')
->willReturn($emailTemplate);
$this->newUserMailHelper
- ->expects($this->at(2))
+ ->expects($this->once())
->method('sendMail')
->with($targetUser, $emailTemplate)
->willThrowException(new \Exception());
$this->api->resendWelcomeMessage('UserToGet');
}
+
+
+ public static function dataGetEditableFields(): array {
+ return [
+ [false, true, ISetDisplayNameBackend::class, [
+ IAccountManager::PROPERTY_EMAIL,
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [true, false, ISetDisplayNameBackend::class, [
+ IAccountManager::PROPERTY_DISPLAYNAME,
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [true, true, ISetDisplayNameBackend::class, [
+ IAccountManager::PROPERTY_DISPLAYNAME,
+ IAccountManager::PROPERTY_EMAIL,
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [false, false, ISetDisplayNameBackend::class, [
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [false, true, UserInterface::class, [
+ IAccountManager::PROPERTY_EMAIL,
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [true, false, UserInterface::class, [
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [true, true, UserInterface::class, [
+ IAccountManager::PROPERTY_EMAIL,
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ [false, false, UserInterface::class, [
+ IAccountManager::COLLECTION_EMAIL,
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_BLUESKY,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_PROFILE_ENABLED,
+ IAccountManager::PROPERTY_PRONOUNS,
+ ]],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetEditableFields')]
+ public function testGetEditableFields(bool $allowedToChangeDisplayName, bool $allowedToChangeEmail, string $userBackend, array $expected): void {
+ $this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => match ($key) {
+ 'allow_user_to_change_display_name' => $allowedToChangeDisplayName,
+ 'allow_user_to_change_email' => $allowedToChangeEmail,
+ default => throw new RuntimeException('Unexpected system config key: ' . $key),
+ });
+
+ $user = $this->createMock(IUser::class);
+ $this->userSession->method('getUser')
+ ->willReturn($user);
+
+ $backend = $this->createMock($userBackend);
+
+ $user->method('getUID')
+ ->willReturn('userId');
+ $user->method('getBackend')
+ ->willReturn($backend);
+
+ $expectedResp = new DataResponse($expected);
+ $this->assertEquals($expectedResp, $this->api->getEditableFields('userId'));
+ }
+
+ private function mockAccount($targetUser, $accountProperties) {
+ $mockedProperties = [];
+
+ foreach ($accountProperties as $propertyName => $data) {
+ $mockedProperty = $this->createMock(IAccountProperty::class);
+ $mockedProperty->method('getValue')->willReturn($data['value'] ?? '');
+ $mockedProperty->method('getScope')->willReturn($data['scope'] ?? '');
+ $mockedProperties[] = [$propertyName, $mockedProperty];
+ }
+
+ $account = $this->createMock(IAccount::class);
+ $account->method('getProperty')
+ ->willReturnMap($mockedProperties);
+
+ $this->accountManager->expects($this->any())->method('getAccount')
+ ->with($targetUser)
+ ->willReturn($account);
+ }
}
diff --git a/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php b/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php
index 2d8b79842f2..c027e518a3d 100644
--- a/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php
+++ b/apps/provisioning_api/tests/Middleware/ProvisioningApiMiddlewareTest.php
@@ -1,66 +1,51 @@
<?php
+
/**
- * @copyright 2016, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Provisioning_API\Tests\Middleware;
use OCA\Provisioning_API\Middleware\Exceptions\NotSubAdminException;
use OCA\Provisioning_API\Middleware\ProvisioningApiMiddleware;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\Utility\IControllerMethodReflector;
use Test\TestCase;
class ProvisioningApiMiddlewareTest extends TestCase {
- /** @var IControllerMethodReflector|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */
private $reflector;
- public function setUp() {
+ protected function setUp(): void {
parent::setUp();
$this->reflector = $this->createMock(IControllerMethodReflector::class);
}
- public function dataAnnotation() {
+ public static function dataAnnotation(): array {
return [
- [false, false, false, false],
- [false, false, true, false],
- [false, true, true, false],
- [ true, false, false, true],
- [ true, false, true, false],
- [ true, true, false, false],
- [ true, true, true, false],
+ [false, false, false, false, false],
+ [false, false, true, false, false],
+ [false, true, true, false, false],
+ [true, false, false, false, true],
+ [true, false, true, false, false],
+ [true, true, false, false, false],
+ [true, true, true, false, false],
+ [false, false, false, true, false],
+ [false, false, true, true, false],
+ [false, true, true, true, false],
+ [true, false, false, true, false],
+ [true, false, true, true, false],
+ [true, true, false, true, false],
+ [true, true, true, true, false],
];
}
- /**
- * @dataProvider dataAnnotation
- *
- * @param bool $subadminRequired
- * @param bool $isAdmin
- * @param bool $isSubAdmin
- * @param bool $shouldThrowException
- */
- public function testBeforeController($subadminRequired, $isAdmin, $isSubAdmin, $shouldThrowException) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAnnotation')]
+ public function testBeforeController(bool $subadminRequired, bool $isAdmin, bool $isSubAdmin, bool $hasSettingAuthorizationAnnotation, bool $shouldThrowException): void {
$middleware = new ProvisioningApiMiddleware(
$this->reflector,
$isAdmin,
@@ -68,8 +53,15 @@ class ProvisioningApiMiddlewareTest extends TestCase {
);
$this->reflector->method('hasAnnotation')
- ->with('NoSubAdminRequired')
- ->willReturn(!$subadminRequired);
+ ->willReturnCallback(function ($annotation) use ($subadminRequired, $hasSettingAuthorizationAnnotation) {
+ if ($annotation === 'NoSubAdminRequired') {
+ return !$subadminRequired;
+ }
+ if ($annotation === 'AuthorizedAdminSetting') {
+ return $hasSettingAuthorizationAnnotation;
+ }
+ return false;
+ });
try {
$middleware->beforeController(
@@ -82,20 +74,15 @@ class ProvisioningApiMiddlewareTest extends TestCase {
}
}
- public function dataAfterException() {
+ public static function dataAfterException(): array {
return [
[new NotSubAdminException(), false],
[new \Exception('test', 42), true],
];
}
- /**
- * @dataProvider dataAfterException
- *
- * @param \Exception $e
- * @param bool $forwared
- */
- public function testAfterException(\Exception $exception, $forwared) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')]
+ public function testAfterException(\Exception $exception, bool $forwared): void {
$middleware = new ProvisioningApiMiddleware(
$this->reflector,
false,
@@ -112,11 +99,10 @@ class ProvisioningApiMiddlewareTest extends TestCase {
} catch (OCSException $e) {
$this->assertFalse($forwared);
$this->assertSame($exception->getMessage(), $e->getMessage());
- $this->assertSame(\OCP\API::RESPOND_UNAUTHORISED, $e->getCode());
+ $this->assertSame(Http::STATUS_FORBIDDEN, $e->getCode());
} catch (\Exception $e) {
$this->assertTrue($forwared);
$this->assertSame($exception, $e);
}
-
}
}
diff --git a/apps/provisioning_api/tests/TestCase.php b/apps/provisioning_api/tests/TestCase.php
index 1ff2c82a3be..30e7f3a4ecf 100644
--- a/apps/provisioning_api/tests/TestCase.php
+++ b/apps/provisioning_api/tests/TestCase.php
@@ -1,38 +1,21 @@
<?php
+
/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
+ * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-
namespace OCA\Provisioning_API\Tests;
+use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
-use OCP\IGroupManager;
+use OCP\Server;
abstract class TestCase extends \Test\TestCase {
/** @var IUser[] */
- protected $users = array();
+ protected $users = [];
/** @var IUserManager */
protected $userManager;
@@ -40,11 +23,11 @@ abstract class TestCase extends \Test\TestCase {
/** @var IGroupManager */
protected $groupManager;
- protected function setUp() {
+ protected function setUp(): void {
parent::setUp();
- $this->userManager = \OC::$server->getUserManager();
- $this->groupManager = \OC::$server->getGroupManager();
+ $this->userManager = Server::get(IUserManager::class);
+ $this->groupManager = Server::get(IGroupManager::class);
$this->groupManager->createGroup('admin');
}
@@ -54,7 +37,7 @@ abstract class TestCase extends \Test\TestCase {
* @return IUser[]|IUser
*/
protected function generateUsers($num = 1) {
- $users = array();
+ $users = [];
for ($i = 0; $i < $num; $i++) {
$user = $this->userManager->createUser($this->getUniqueID(), 'password');
$this->users[] = $user;
@@ -63,8 +46,8 @@ abstract class TestCase extends \Test\TestCase {
return count($users) == 1 ? reset($users) : $users;
}
- protected function tearDown() {
- foreach($this->users as $user) {
+ protected function tearDown(): void {
+ foreach ($this->users as $user) {
$user->delete();
}