]> source.dussan.org Git - nextcloud-server.git/commitdiff
provisioning_api: Add OpenAPI spec 39223/head
authorjld3103 <jld3103yt@gmail.com>
Wed, 15 Feb 2023 18:27:04 +0000 (19:27 +0100)
committerjld3103 <jld3103yt@gmail.com>
Mon, 31 Jul 2023 08:29:08 +0000 (10:29 +0200)
Signed-off-by: jld3103 <jld3103yt@gmail.com>
15 files changed:
apps/provisioning_api/composer/composer/autoload_classmap.php
apps/provisioning_api/composer/composer/autoload_static.php
apps/provisioning_api/lib/Capabilities.php
apps/provisioning_api/lib/Controller/AUserData.php
apps/provisioning_api/lib/Controller/AppConfigController.php
apps/provisioning_api/lib/Controller/AppsController.php
apps/provisioning_api/lib/Controller/GroupsController.php
apps/provisioning_api/lib/Controller/PreferencesController.php
apps/provisioning_api/lib/Controller/UsersController.php
apps/provisioning_api/lib/Controller/VerificationController.php
apps/provisioning_api/lib/ResponseDefinitions.php [new file with mode: 0644]
apps/provisioning_api/openapi.json
lib/private/AppConfig.php
lib/private/legacy/OC_Helper.php
lib/public/IAppConfig.php

index 12c2daf7a1406e10add7386086748651582eda23..d702db318db2c9d5e46b4f8181e5055f6e58c3e5 100644 (file)
@@ -20,4 +20,5 @@ return array(
     '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',
 );
index 5aadb1574b3550a0a9ef89b314a4175ab802503b..4c987e24fc99a936fa50905406eff5de75e97656 100644 (file)
@@ -35,6 +35,7 @@ class ComposerStaticInitProvisioning_API
         '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)
index 614c20e66a8a1065c6d7b1b6f556d0c79e799e0b..3504868fcf32e868aef122160b296bbaf046a531 100644 (file)
@@ -3,6 +3,7 @@
  * @copyright Copyright (c) 2021 Vincent Petry <vincent@nextcloud.com>
  *
  * @author Vincent Petry <vincent@nextcloud.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -37,6 +38,15 @@ class Capabilities implements ICapability {
 
        /**
         * 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');
index 128fda588e28150c5e8a9938225daf883f034079..7ce1484cf714c92053f6c675e9b2423a36c16c28 100644 (file)
@@ -36,6 +36,7 @@ use OC\Group\Manager;
 use OC\User\Backend;
 use OC\User\NoUserException;
 use OC_Helper;
+use OCA\Provisioning_API\ResponseDefinitions;
 use OCP\Accounts\IAccountManager;
 use OCP\Accounts\PropertyDoesNotExistException;
 use OCP\AppFramework\Http;
@@ -52,6 +53,10 @@ use OCP\L10N\IFactory;
 use OCP\User\Backend\ISetDisplayNameBackend;
 use OCP\User\Backend\ISetPasswordBackend;
 
+/**
+ * @psalm-import-type ProvisioningApiUserDetails from ResponseDefinitions
+ * @psalm-import-type ProvisioningApiUserDetailsQuota from ResponseDefinitions
+ */
 abstract class AUserData extends OCSController {
        public const SCOPE_SUFFIX = 'Scope';
 
@@ -99,12 +104,12 @@ abstract class AUserData extends OCSController {
         *
         * @param string $userId
         * @param bool $includeScopes
-        * @return array
+        * @return ProvisioningApiUserDetails|null
         * @throws NotFoundException
         * @throws OCSException
         * @throws OCSNotFoundException
         */
-       protected function getUserData(string $userId, bool $includeScopes = false): array {
+       protected function getUserData(string $userId, bool $includeScopes = false): ?array {
                $currentLoggedInUser = $this->userSession->getUser();
                assert($currentLoggedInUser !== null, 'No user logged in');
 
@@ -123,7 +128,7 @@ abstract class AUserData extends OCSController {
                } else {
                        // Check they are looking up themselves
                        if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
-                               return $data;
+                               return null;
                        }
                }
 
@@ -225,7 +230,7 @@ abstract class AUserData extends OCSController {
         * Get the groups a user is a subadmin of
         *
         * @param string $userId
-        * @return array
+        * @return string[]
         * @throws OCSException
         */
        protected function getUserSubAdminGroupsData(string $userId): array {
@@ -247,7 +252,7 @@ abstract class AUserData extends OCSController {
 
        /**
         * @param string $userId
-        * @return array
+        * @return ProvisioningApiUserDetailsQuota
         * @throws OCSException
         */
        protected function fillStorageInfo(string $userId): array {
index 929676be16ec158670ef4d2f006a981f668507a2..b6e2bec0ccddbc3d4f936ce75df4d60dd261e0d4 100644 (file)
@@ -7,6 +7,7 @@ declare(strict_types=1);
  *
  * @author Joas Schilling <coding@schilljs.com>
  * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -84,7 +85,9 @@ class AppConfigController extends OCSController {
        }
 
        /**
-        * @return DataResponse
+        * Get a list of apps
+        *
+        * @return DataResponse<Http::STATUS_OK, array{data: string[]}, array{}>
         */
        public function getApps(): DataResponse {
                return new DataResponse([
@@ -93,8 +96,13 @@ class AppConfigController extends OCSController {
        }
 
        /**
-        * @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: string[]}, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
+        *
+        * 200: Keys returned
+        * 403: App is not allowed
         */
        public function getKeys(string $app): DataResponse {
                try {
@@ -108,10 +116,15 @@ class AppConfigController extends OCSController {
        }
 
        /**
-        * @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(string $app, string $key, string $defaultValue = ''): DataResponse {
                try {
@@ -128,10 +141,16 @@ class AppConfigController extends OCSController {
         * @PasswordConfirmationRequired
         * @NoSubAdminRequired
         * @NoAdminRequired
-        * @param string $app
-        * @param string $key
-        * @param string $value
-        * @return DataResponse
+        *
+        * 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, array<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(string $app, string $key, string $value): DataResponse {
                $user = $this->userSession->getUser();
@@ -156,9 +175,15 @@ class AppConfigController extends OCSController {
 
        /**
         * @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, array<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(string $app, string $key): DataResponse {
                try {
index fa0f2597e7fde4f5c4d24b776717c1a61011e68d..7f84bdeb9db6bf6fee5a062d299ad3ce50095406 100644 (file)
@@ -10,6 +10,7 @@ declare(strict_types=1);
  * @author Lukas Reschke <lukas@statuscode.ch>
  * @author Roeland Jago Douma <roeland@famdouma.nl>
  * @author Tom Needham <tom@owncloud.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
  *
  * @license AGPL-3.0
  *
@@ -29,13 +30,18 @@ declare(strict_types=1);
 namespace OCA\Provisioning_API\Controller;
 
 use OC_App;
+use OCA\Provisioning_API\ResponseDefinitions;
 use OCP\App\AppPathNotFoundException;
 use OCP\App\IAppManager;
+use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\DataResponse;
 use OCP\AppFramework\OCS\OCSException;
 use OCP\AppFramework\OCSController;
 use OCP\IRequest;
 
+/**
+ * @psalm-import-type ProvisioningApiAppInfo from ResponseDefinitions
+ */
 class AppsController extends OCSController {
        /** @var IAppManager */
        private $appManager;
@@ -51,16 +57,19 @@ class AppsController extends OCSController {
        }
 
        /**
-        * @param string|null $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: string[]}, array{}>
         * @throws OCSException
         */
-       public function getApps(string $filter = null): DataResponse {
+       public function getApps(?string $filter = null): DataResponse {
                $apps = (new OC_App())->listAllApps();
                $list = [];
                foreach ($apps as $app) {
                        $list[] = $app['id'];
                }
+               /** @var string[] $list */
                if ($filter) {
                        switch ($filter) {
                                case 'enabled':
@@ -80,8 +89,10 @@ class AppsController extends OCSController {
        }
 
        /**
-        * @param string $app
-        * @return DataResponse
+        * Get the app info for an app
+        *
+        * @param string $app ID of the app
+        * @return DataResponse<Http::STATUS_OK, ProvisioningApiAppInfo, array{}>
         * @throws OCSException
         */
        public function getAppInfo(string $app): DataResponse {
@@ -95,8 +106,11 @@ class AppsController extends OCSController {
 
        /**
         * @PasswordConfirmationRequired
-        * @param string $app
-        * @return DataResponse
+        *
+        * Enable an app
+        *
+        * @param string $app ID of the app
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function enable(string $app): DataResponse {
@@ -110,8 +124,11 @@ class AppsController extends OCSController {
 
        /**
         * @PasswordConfirmationRequired
-        * @param string $app
-        * @return DataResponse
+        *
+        * Disable an app
+        *
+        * @param string $app ID of the app
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         */
        public function disable(string $app): DataResponse {
                $this->appManager->disableApp($app);
index 46de5395a656021b554c7a86be8dbce7c63992bd..5404f47efc2181120f74d1f4119f83c0e67790f5 100644 (file)
@@ -14,6 +14,7 @@ declare(strict_types=1);
  * @author Robin Appelman <robin@icewind.nl>
  * @author Roeland Jago Douma <roeland@famdouma.nl>
  * @author Tom Needham <tom@owncloud.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
  *
  * @license AGPL-3.0
  *
@@ -32,7 +33,9 @@ declare(strict_types=1);
  */
 namespace OCA\Provisioning_API\Controller;
 
+use OCA\Provisioning_API\ResponseDefinitions;
 use OCP\Accounts\IAccountManager;
+use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\DataResponse;
 use OCP\AppFramework\OCS\OCSException;
 use OCP\AppFramework\OCS\OCSForbiddenException;
@@ -48,6 +51,10 @@ use OCP\IUserSession;
 use OCP\L10N\IFactory;
 use Psr\Log\LoggerInterface;
 
+/**
+ * @psalm-import-type ProvisioningApiGroupDetails from ResponseDefinitions
+ * @psalm-import-type ProvisioningApiUserDetails from ResponseDefinitions
+ */
 class GroupsController extends AUserData {
 
        /** @var LoggerInterface */
@@ -76,16 +83,16 @@ class GroupsController extends AUserData {
        }
 
        /**
-        * returns a list of groups
-        *
         * @NoAdminRequired
         *
-        * @param string $search
-        * @param int $limit
-        * @param int $offset
-        * @return DataResponse
+        * 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: string[]}, array{}>
         */
-       public function getGroups(string $search = '', int $limit = null, int $offset = 0): DataResponse {
+       public function getGroups(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
                $groups = $this->groupManager->search($search, $limit, $offset);
                $groups = array_map(function ($group) {
                        /** @var IGroup $group */
@@ -96,15 +103,15 @@ class GroupsController extends AUserData {
        }
 
        /**
-        * Returns a list of groups details with ids and displaynames
-        *
         * @NoAdminRequired
         * @AuthorizedAdminSetting(settings=OCA\Settings\Settings\Admin\Sharing)
         *
-        * @param string $search
-        * @param int $limit
-        * @param int $offset
-        * @return DataResponse
+        * Get a list of groups details
+        *
+        * @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: ProvisioningApiGroupDetails[]}, array{}>
         */
        public function getGroupsDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
                $groups = $this->groupManager->search($search, $limit, $offset);
@@ -126,8 +133,10 @@ class GroupsController extends AUserData {
        /**
         * @NoAdminRequired
         *
-        * @param string $groupId
-        * @return DataResponse
+        * Get a list of users in the specified group
+        *
+        * @param string $groupId ID of the group
+        * @return DataResponse<Http::STATUS_OK, array{users: string[]}, array{}>
         * @throws OCSException
         *
         * @deprecated 14 Use getGroupUsers
@@ -137,13 +146,17 @@ class GroupsController extends AUserData {
        }
 
        /**
-        * returns an array of users in the specified group
-        *
         * @NoAdminRequired
         *
-        * @param string $groupId
-        * @return DataResponse
+        * Get a list of users in the specified group
+        *
+        * @param string $groupId ID of the group
+        * @return DataResponse<Http::STATUS_OK, array{users: 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 getGroupUsers(string $groupId): DataResponse {
                $groupId = urldecode($groupId);
@@ -167,6 +180,7 @@ class GroupsController extends AUserData {
                                /** @var IUser $user */
                                return $user->getUID();
                        }, $users);
+                       /** @var string[] $users */
                        $users = array_values($users);
                        return new DataResponse(['users' => $users]);
                }
@@ -175,15 +189,16 @@ class GroupsController extends AUserData {
        }
 
        /**
-        * returns an array of users details in the specified group
-        *
         * @NoAdminRequired
         *
-        * @param string $groupId
-        * @param string $search
-        * @param int $limit
-        * @param int $offset
-        * @return DataResponse
+        * Get a list of users details in the specified group
+        *
+        * @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
+        *
+        * @return DataResponse<Http::STATUS_OK, array{users: array<string, ProvisioningApiUserDetails|array{id: string}>}, array{}>
         * @throws OCSException
         */
        public function getGroupUsersDetails(string $groupId, string $search = '', int $limit = null, int $offset = 0): DataResponse {
@@ -210,7 +225,7 @@ class GroupsController extends AUserData {
                                        $userId = (string)$user->getUID();
                                        $userData = $this->getUserData($userId);
                                        // Do not insert empty entry
-                                       if (!empty($userData)) {
+                                       if ($userData !== null) {
                                                $usersDetails[$userId] = $userData;
                                        } else {
                                                // Logged user does not have permissions to see this user
@@ -228,13 +243,13 @@ class GroupsController extends AUserData {
        }
 
        /**
-        * creates a new group
-        *
         * @PasswordConfirmationRequired
         *
-        * @param string $groupid
-        * @param string $displayname
-        * @return DataResponse
+        * Create a new group
+        *
+        * @param string $groupid ID of the group
+        * @param string $displayname Display name of the group
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function addGroup(string $groupid, string $displayname = ''): DataResponse {
@@ -260,10 +275,12 @@ class GroupsController extends AUserData {
        /**
         * @PasswordConfirmationRequired
         *
-        * @param string $groupId
-        * @param string $key
-        * @param string $value
-        * @return DataResponse
+        * 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, array<empty>, array{}>
         * @throws OCSException
         */
        public function updateGroup(string $groupId, string $key, string $value): DataResponse {
@@ -287,8 +304,10 @@ class GroupsController extends AUserData {
        /**
         * @PasswordConfirmationRequired
         *
-        * @param string $groupId
-        * @return DataResponse
+        * Delete a group
+        *
+        * @param string $groupId ID of the group
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function deleteGroup(string $groupId): DataResponse {
@@ -306,8 +325,10 @@ class GroupsController extends AUserData {
        }
 
        /**
-        * @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, string[], array{}>
         * @throws OCSException
         */
        public function getSubAdminsOfGroup(string $groupId): DataResponse {
@@ -320,6 +341,7 @@ class GroupsController extends AUserData {
                /** @var IUser[] $subadmins */
                $subadmins = $this->groupManager->getSubAdmin()->getGroupsSubAdmins($targetGroup);
                // New class returns IUser[] so convert back
+               /** @var string[] $uids */
                $uids = [];
                foreach ($subadmins as $user) {
                        $uids[] = $user->getUID();
index 2dba8b86eb6fc551aa6818158f0e2f24f9f4b000..cc7a9efd764b1acaf83f6c8b5a6eb3162aa3c04e 100644 (file)
@@ -6,6 +6,7 @@ declare(strict_types=1);
  * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
  *
  * @author Joas Schilling <coding@schilljs.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -58,6 +59,16 @@ class PreferencesController extends OCSController {
        /**
         * @NoAdminRequired
         * @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, array<empty>, array{}>
+        *
+        * 200: Preferences updated successfully
+        * 400: Preference invalid
         */
        public function setMultiplePreferences(string $appId, array $configs): DataResponse {
                $userId = $this->userSession->getUser()->getUID();
@@ -93,6 +104,16 @@ class PreferencesController extends OCSController {
        /**
         * @NoAdminRequired
         * @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, array<empty>, array{}>
+        *
+        * 200: Preference updated successfully
+        * 400: Preference invalid
         */
        public function setPreference(string $appId, string $configKey, string $configValue): DataResponse {
                $userId = $this->userSession->getUser()->getUID();
@@ -124,6 +145,15 @@ class PreferencesController extends OCSController {
        /**
         * @NoAdminRequired
         * @NoSubAdminRequired
+        *
+        * Delete multiple preferences for an app
+        *
+        * @param string $appId ID of the app
+        * @param string[] $configKeys Keys to delete
+        *
+        * @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, array<empty>, array{}>
+        * 200: Preferences deleted successfully
+        * 400: Preference invalid
         */
        public function deleteMultiplePreference(string $appId, array $configKeys): DataResponse {
                $userId = $this->userSession->getUser()->getUID();
@@ -157,6 +187,15 @@ class PreferencesController extends OCSController {
        /**
         * @NoAdminRequired
         * @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, array<empty>, array{}>
+        *
+        * 200: Preference deleted successfully
+        * 400: Preference invalid
         */
        public function deletePreference(string $appId, string $configKey): DataResponse {
                $userId = $this->userSession->getUser()->getUID();
index 6ce46087d8042932133eef724e74c1f343cbf343..07f651c74fa4e25cb903e9664ed874e878b5a170 100644 (file)
@@ -51,6 +51,7 @@ use libphonenumber\PhoneNumberUtil;
 use OC\Authentication\Token\RemoteWipe;
 use OC\KnownUser\KnownUserService;
 use OC\User\Backend;
+use OCA\Provisioning_API\ResponseDefinitions;
 use OCA\Settings\Mailer\NewUserMailHelper;
 use OCP\Accounts\IAccountManager;
 use OCP\Accounts\IAccountProperty;
@@ -76,6 +77,9 @@ use OCP\Security\ISecureRandom;
 use OCP\User\Backend\ISetDisplayNameBackend;
 use Psr\Log\LoggerInterface;
 
+/**
+ * @psalm-import-type ProvisioningApiUserDetails from ResponseDefinitions
+ */
 class UsersController extends AUserData {
        /** @var IURLGenerator */
        protected $urlGenerator;
@@ -135,12 +139,12 @@ class UsersController extends AUserData {
        /**
         * @NoAdminRequired
         *
-        * returns a list of users
+        * Get a list of users
         *
-        * @param string $search
-        * @param int $limit
-        * @param int $offset
-        * @return DataResponse
+        * @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: string[]}, array{}>
         */
        public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
                $user = $this->userSession->getUser();
@@ -163,6 +167,7 @@ class UsersController extends AUserData {
                        }
                }
 
+               /** @var string[] $users */
                $users = array_keys($users);
 
                return new DataResponse([
@@ -173,7 +178,12 @@ class UsersController extends AUserData {
        /**
         * @NoAdminRequired
         *
-        * returns a list of users and their data
+        * 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, ProvisioningApiUserDetails|array{id: string}>}, array{}>
         */
        public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
                $currentUser = $this->userSession->getUser();
@@ -198,12 +208,13 @@ class UsersController extends AUserData {
                        $users = array_merge(...$users);
                }
 
+               /** @var array<string, ProvisioningApiUserDetails|array{id: string}> $usersDetails */
                $usersDetails = [];
                foreach ($users as $userId) {
                        $userId = (string) $userId;
                        $userData = $this->getUserData($userId);
                        // Do not insert empty entry
-                       if (!empty($userData)) {
+                       if ($userData !== null) {
                                $usersDetails[$userId] = $userData;
                        } else {
                                // Logged user does not have permissions to see this user
@@ -222,9 +233,14 @@ class UsersController extends AUserData {
         * @NoAdminRequired
         * @NoSubAdminRequired
         *
-        * @param string $location
-        * @param array $search
-        * @return DataResponse
+        * Search users by their phone numbers
+        *
+        * @param string $location Location of the phone number (for country code)
+        * @param array<string, string[]> $search Phone numbers to search for
+        * @return DataResponse<Http::STATUS_OK, array<string, string>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array<empty>, array{}>
+        *
+        * 200: Users returned
+        * 400: Invalid location
         */
        public function searchByPhoneNumbers(string $location, array $search): DataResponse {
                $phoneUtil = PhoneNumberUtil::getInstance();
@@ -318,16 +334,22 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userid
-        * @param string $password
-        * @param string $displayName
-        * @param string $email
-        * @param array $groups
-        * @param array $subadmin
-        * @param string $quota
-        * @param string $language
-        * @return DataResponse
+        * Create a new user
+        *
+        * @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 string[] $groups Groups of the user
+        * @param 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(
                string $userid,
@@ -521,10 +543,10 @@ class UsersController extends AUserData {
         * @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, ProvisioningApiUserDetails, array{}>
         * @throws OCSException
         */
        public function getUser(string $userId): DataResponse {
@@ -535,8 +557,8 @@ class UsersController extends AUserData {
                }
 
                $data = $this->getUserData($userId, $includeScopes);
-               // getUserData returns empty array if not enough permissions
-               if (empty($data)) {
+               // getUserData returns null if not enough permissions
+               if ($data === null) {
                        throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
                }
                return new DataResponse($data);
@@ -546,14 +568,15 @@ class UsersController extends AUserData {
         * @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, ProvisioningApiUserDetails, array{}>
         * @throws OCSException
         */
        public function getCurrentUser(): DataResponse {
                $user = $this->userSession->getUser();
                if ($user) {
+                       /** @var ProvisioningApiUserDetails $data */
                        $data = $this->getUserData($user->getUID(), true);
                        return new DataResponse($data);
                }
@@ -565,7 +588,9 @@ class UsersController extends AUserData {
         * @NoAdminRequired
         * @NoSubAdminRequired
         *
-        * @return DataResponse
+        * Get a list of fields that are editable for the current user
+        *
+        * @return DataResponse<Http::STATUS_OK, string[], array{}>
         * @throws OCSException
         */
        public function getEditableFields(): DataResponse {
@@ -581,8 +606,10 @@ class UsersController extends AUserData {
         * @NoAdminRequired
         * @NoSubAdminRequired
         *
-        * @param string $userId
-        * @return DataResponse
+        * Get a list of fields that are editable for a user
+        *
+        * @param string $userId ID of the user
+        * @return DataResponse<Http::STATUS_OK, string[], array{}>
         * @throws OCSException
         */
        public function getEditableFieldsForUser(string $userId): DataResponse {
@@ -642,6 +669,13 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @UserRateThrottle(limit=5, period=60)
         *
+        * 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, array<empty>, array{}>
         * @throws OCSException
         */
        public function editUserMultiValue(
@@ -735,12 +769,12 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @UserRateThrottle(limit=50, period=600)
         *
-        * 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, array<empty>, array{}>
         * @throws OCSException
         */
        public function editUser(string $userId, string $key, string $value): DataResponse {
@@ -1046,9 +1080,11 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userId
+        * Wipe all devices of a user
         *
-        * @return DataResponse
+        * @param string $userId ID of the user
+        *
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         *
         * @throws OCSException
         */
@@ -1081,8 +1117,10 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userId
-        * @return DataResponse
+        * Delete a user
+        *
+        * @param string $userId ID of the user
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function deleteUser(string $userId): DataResponse {
@@ -1116,10 +1154,11 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userId
-        * @return DataResponse
+        * Disable a user
+        *
+        * @param string $userId ID of the user
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
-        * @throws OCSForbiddenException
         */
        public function disableUser(string $userId): DataResponse {
                return $this->setEnabled($userId, false);
@@ -1129,10 +1168,11 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userId
-        * @return DataResponse
+        * Enable a user
+        *
+        * @param string $userId ID of the user
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
-        * @throws OCSForbiddenException
         */
        public function enableUser(string $userId): DataResponse {
                return $this->setEnabled($userId, true);
@@ -1141,7 +1181,7 @@ class UsersController extends AUserData {
        /**
         * @param string $userId
         * @param bool $value
-        * @return DataResponse
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        private function setEnabled(string $userId, bool $value): DataResponse {
@@ -1167,8 +1207,10 @@ class UsersController extends AUserData {
         * @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: string[]}, array{}>
         * @throws OCSException
         */
        public function getUsersGroups(string $userId): DataResponse {
@@ -1195,6 +1237,7 @@ class UsersController extends AUserData {
                                foreach ($getSubAdminsGroups as $key => $group) {
                                        $getSubAdminsGroups[$key] = $group->getGID();
                                }
+                               /** @var string[] $groups */
                                $groups = array_intersect(
                                        $getSubAdminsGroups,
                                        $this->groupManager->getUserGroupIds($targetUser)
@@ -1211,9 +1254,11 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userId
-        * @param string $groupid
-        * @return DataResponse
+        * 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, array<empty>, array{}>
         * @throws OCSException
         */
        public function addToGroup(string $userId, string $groupid = ''): DataResponse {
@@ -1246,9 +1291,11 @@ class UsersController extends AUserData {
         * @PasswordConfirmationRequired
         * @NoAdminRequired
         *
-        * @param string $userId
-        * @param string $groupid
-        * @return DataResponse
+        * Remove a user from a group
+        *
+        * @param string $userId ID of the user
+        * @param string $groupid ID of the group
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function removeFromGroup(string $userId, string $groupid): DataResponse {
@@ -1305,13 +1352,13 @@ class UsersController extends AUserData {
        }
 
        /**
-        * Creates a subadmin
-        *
         * @PasswordConfirmationRequired
         *
-        * @param string $userId
-        * @param string $groupid
-        * @return DataResponse
+        * Make a user a subadmin of a group
+        *
+        * @param string $userId ID of the user
+        * @param string $groupid ID of the group
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function addSubAdmin(string $userId, string $groupid): DataResponse {
@@ -1343,13 +1390,13 @@ class UsersController extends AUserData {
        }
 
        /**
-        * Removes a subadmin from a group
-        *
         * @PasswordConfirmationRequired
         *
-        * @param string $userId
-        * @param string $groupid
-        * @return DataResponse
+        * Remove a user from the subadmins of a group
+        *
+        * @param string $userId ID of the user
+        * @param string $groupid ID of the group
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function removeSubAdmin(string $userId, string $groupid): DataResponse {
@@ -1378,8 +1425,8 @@ class UsersController extends AUserData {
        /**
         * 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, string[], array{}>
         * @throws OCSException
         */
        public function getUserSubAdminGroups(string $userId): DataResponse {
@@ -1391,10 +1438,10 @@ class UsersController extends AUserData {
         * @NoAdminRequired
         * @PasswordConfirmationRequired
         *
-        * resend welcome message
+        * Resend the welcome message
         *
-        * @param string $userId
-        * @return DataResponse
+        * @param string $userId ID if the user
+        * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
         * @throws OCSException
         */
        public function resendWelcomeMessage(string $userId): DataResponse {
index f16f50385e7795d01cdcd5441379120683ea6170..0b04a0d7218e351cc848590b388e427421b38029 100644 (file)
@@ -6,6 +6,7 @@ declare(strict_types=1);
  * @copyright Copyright (c) 2021 Arthur Schiwon <blizzz@arthur-schiwon.de>
  *
  * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -30,6 +31,7 @@ use InvalidArgumentException;
 use OC\Security\Crypto;
 use OCP\Accounts\IAccountManager;
 use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\IgnoreOpenAPI;
 use OCP\AppFramework\Http\TemplateResponse;
 use OCP\IL10N;
 use OCP\IRequest;
@@ -38,6 +40,7 @@ use OCP\IUserSession;
 use OCP\Security\VerificationToken\InvalidTokenException;
 use OCP\Security\VerificationToken\IVerificationToken;
 
+#[IgnoreOpenAPI]
 class VerificationController extends Controller {
 
        /** @var IVerificationToken */
diff --git a/apps/provisioning_api/lib/ResponseDefinitions.php b/apps/provisioning_api/lib/ResponseDefinitions.php
new file mode 100644 (file)
index 0000000..4e562ec
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Provisioning_API;
+
+/**
+ * @psalm-type ProvisioningApiUserDetailsQuota = array{
+ *     free?: float,
+ *     quota?: float|string,
+ *     relative?: float,
+ *     total?: float,
+ *     used?: float,
+ * }
+ *
+ * @psalm-type ProvisioningApiUserDetails = array{
+ *     additional_mail: string[],
+ *     additional_mailScope?: string[],
+ *     address: string,
+ *     addressScope?: string,
+ *     avatarScope?: string,
+ *     backend: string,
+ *     backendCapabilities: array{
+ *         setDisplayName: bool,
+ *         setPassword: bool
+ *     },
+ *     biography: string,
+ *     biographyScope?: string,
+ *     display-name: string,
+ *     displayname: string,
+ *     displaynameScope?: string,
+ *     email: ?string,
+ *     emailScope?: string,
+ *     enabled?: bool,
+ *     fediverse: string,
+ *     fediverseScope?: string,
+ *     groups: string[],
+ *     headline: string,
+ *     headlineScope?: string,
+ *     id: string,
+ *     language: string,
+ *     lastLogin: int,
+ *     locale: string,
+ *     manager: string,
+ *     notify_email: ?string,
+ *     organisation: string,
+ *     organisationScope?: string,
+ *     phone: string,
+ *     phoneScope?: string,
+ *     profile_enabled: string,
+ *     profile_enabledScope?: string,
+ *     quota: ProvisioningApiUserDetailsQuota,
+ *     role: string,
+ *     roleScope?: string,
+ *     storageLocation?: string,
+ *     subadmin: string[],
+ *     twitter: string,
+ *     twitterScope?: string,
+ *     website: string,
+ *     websiteScope?: string,
+ * }
+ *
+ * @psalm-type ProvisioningApiAppInfo = array{
+ *     active: bool|null,
+ *     activity: ?mixed,
+ *     author: ?mixed,
+ *     background-jobs: ?mixed,
+ *     bugs: ?mixed,
+ *     category: ?mixed,
+ *     collaboration: ?mixed,
+ *     commands: ?mixed,
+ *     default_enable: ?mixed,
+ *     dependencies: ?mixed,
+ *     description: string,
+ *     discussion: ?mixed,
+ *     documentation: ?mixed,
+ *     groups: ?mixed,
+ *     id: string,
+ *     info: ?mixed,
+ *     internal: bool|null,
+ *     level: int|null,
+ *     licence: ?mixed,
+ *     name: string,
+ *     namespace: ?mixed,
+ *     navigations: ?mixed,
+ *     preview: ?mixed,
+ *     previewAsIcon: bool|null,
+ *     public: ?mixed,
+ *     remote: ?mixed,
+ *     removable: bool|null,
+ *     repair-steps: ?mixed,
+ *     repository: ?mixed,
+ *     sabre: ?mixed,
+ *     screenshot: ?mixed,
+ *     settings: ?mixed,
+ *     summary: string,
+ *     trash: ?mixed,
+ *     two-factor-providers: ?mixed,
+ *     types: ?mixed,
+ *     version: string,
+ *     versions: ?mixed,
+ *     website: ?mixed,
+ * }
+ *
+ * @psalm-type ProvisioningApiGroupDetails = array{
+ *     id: string,
+ *     displayname: string,
+ *     usercount: bool|int,
+ *     disabled: bool|int,
+ *     canAdd: bool,
+ *     canRemove: bool,
+ * }
+ */
+class ResponseDefinitions {
+}
index 82ee9b16e31974ec9c8b1e81dd61b9716384ed48..6eb16aa6ad17bd9de13bbf930caed61479ba9a14 100644 (file)
                 "type": "object",
                 "required": [
                     "additional_mail",
-                    "additional_mailScope",
                     "address",
-                    "addressScope",
-                    "avatarScope",
                     "backend",
                     "backendCapabilities",
                     "biography",
-                    "biographyScope",
-                    "displayname",
                     "display-name",
-                    "displaynameScope",
+                    "displayname",
                     "email",
-                    "emailScope",
-                    "enabled",
                     "fediverse",
-                    "fediverseScope",
                     "groups",
                     "headline",
-                    "headlineScope",
                     "id",
                     "language",
                     "lastLogin",
                     "locale",
+                    "manager",
                     "notify_email",
                     "organisation",
-                    "organisationScope",
                     "phone",
-                    "phoneScope",
                     "profile_enabled",
-                    "profile_enabledScope",
                     "quota",
                     "role",
-                    "roleScope",
-                    "storageLocation",
                     "subadmin",
                     "twitter",
-                    "twitterScope",
-                    "website",
-                    "websiteScope"
+                    "website"
                 ],
                 "properties": {
                     "additional_mail": {
                     },
                     "additional_mailScope": {
                         "type": "array",
-                        "nullable": true,
                         "items": {
                             "type": "string"
                         }
                         "type": "string"
                     },
                     "addressScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "avatarScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "backend": {
                         "type": "string"
                         "type": "string"
                     },
                     "biographyScope": {
-                        "type": "string",
-                        "nullable": true
-                    },
-                    "displayname": {
                         "type": "string"
                     },
                     "display-name": {
                         "type": "string"
                     },
+                    "displayname": {
+                        "type": "string"
+                    },
                     "displaynameScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "email": {
                         "type": "string",
                         "nullable": true
                     },
                     "emailScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "enabled": {
-                        "type": "boolean",
-                        "nullable": true
+                        "type": "boolean"
                     },
                     "fediverse": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "fediverseScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "groups": {
                         "type": "array",
                         "type": "string"
                     },
                     "headlineScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "id": {
                         "type": "string"
                     "locale": {
                         "type": "string"
                     },
+                    "manager": {
+                        "type": "string"
+                    },
                     "notify_email": {
                         "type": "string",
                         "nullable": true
                         "type": "string"
                     },
                     "organisationScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "phone": {
                         "type": "string"
                     },
                     "phoneScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "profile_enabled": {
                         "type": "string"
                     },
                     "profile_enabledScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "quota": {
-                        "type": "object",
-                        "required": [
-                            "free",
-                            "quota",
-                            "relative",
-                            "total",
-                            "used"
-                        ],
-                        "properties": {
-                            "free": {
-                                "type": "integer",
-                                "format": "int64",
-                                "nullable": true
-                            },
-                            "quota": {
-                                "oneOf": [
-                                    {
-                                        "type": "string"
-                                    },
-                                    {
-                                        "type": "integer",
-                                        "format": "int64"
-                                    },
-                                    {
-                                        "type": "boolean"
-                                    }
-                                ]
-                            },
-                            "relative": {
-                                "type": "number",
-                                "format": "float",
-                                "nullable": true
-                            },
-                            "total": {
-                                "type": "integer",
-                                "format": "int64",
-                                "nullable": true
-                            },
-                            "used": {
-                                "type": "integer",
-                                "format": "int64"
-                            }
-                        }
+                        "$ref": "#/components/schemas/UserDetailsQuota"
                     },
                     "role": {
                         "type": "string"
                     },
                     "roleScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "storageLocation": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "subadmin": {
                         "type": "array",
                         "type": "string"
                     },
                     "twitterScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
                     },
                     "website": {
                         "type": "string"
                     },
                     "websiteScope": {
-                        "type": "string",
-                        "nullable": true
+                        "type": "string"
+                    }
+                }
+            },
+            "UserDetailsQuota": {
+                "type": "object",
+                "properties": {
+                    "free": {
+                        "type": "number",
+                        "format": "float"
+                    },
+                    "quota": {
+                        "oneOf": [
+                            {
+                                "type": "number",
+                                "format": "float"
+                            },
+                            {
+                                "type": "string"
+                            }
+                        ]
+                    },
+                    "relative": {
+                        "type": "number",
+                        "format": "float"
+                    },
+                    "total": {
+                        "type": "number",
+                        "format": "float"
+                    },
+                    "used": {
+                        "type": "number",
+                        "format": "float"
                     }
                 }
             }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                         }
                     },
                     "403": {
-                        "description": "App not allowed",
+                        "description": "App is not allowed",
                         "content": {
                             "application/json": {
                                 "schema": {
                         }
                     },
                     "403": {
-                        "description": "App not allowed",
+                        "description": "App is not allowed",
                         "content": {
                             "application/json": {
                                 "schema": {
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                         }
                     },
                     "403": {
-                        "description": "App or key not allowed",
+                        "description": "App or key is not allowed",
                         "content": {
                             "application/json": {
                                 "schema": {
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                         }
                     },
                     "403": {
-                        "description": "App or key not allowed",
+                        "description": "App or key is not allowed",
                         "content": {
                             "application/json": {
                                 "schema": {
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
                                                 "meta": {
                                                     "$ref": "#/components/schemas/OCSMeta"
                                                 },
-                                                "data": {
-                                                    "type": "object",
-                                                    "additionalProperties": true
-                                                }
+                                                "data": {}
                                             }
                                         }
                                     }
index 96fa6bf74672110724a382a2852b88466f50d96e..84f0d5b9e5add5d2fbf334690f6dd9cb8e8f21f7 100644 (file)
@@ -175,7 +175,7 @@ class AppConfig implements IAppConfig {
        /**
         * Get all apps using the config
         *
-        * @return array an array of app ids
+        * @return string[] an array of app ids
         *
         * This function returns a list of all apps that have at least one
         * entry in the appconfig table.
index 8c8be0e1069d0932c6b94ed4b917497d617145d5..d96cb7bb4e9850e88e244888e49ad78cf9e11eea 100644 (file)
@@ -54,6 +54,18 @@ use Psr\Log\LoggerInterface;
 
 /**
  * Collection of useful functions
+ *
+ * @psalm-type StorageInfo = array{
+ *     free: float|int,
+ *     mountPoint: string,
+ *     mountType: string,
+ *     owner: string,
+ *     ownerDisplayName: string,
+ *     quota: float|int,
+ *     relative: float|int,
+ *     total: float|int,
+ *     used: float|int,
+ * }
  */
 class OC_Helper {
        private static $templateManager;
@@ -458,7 +470,8 @@ class OC_Helper {
         * @param \OCP\Files\FileInfo $rootInfo (optional)
         * @param bool $includeMountPoints whether to include mount points in the size calculation
         * @param bool $useCache whether to use the cached quota values
-        * @return array
+        * @psalm-suppress LessSpecificReturnStatement Legacy code outputs weird types - manually validated that they are correct
+        * @return StorageInfo
         * @throws \OCP\Files\NotFoundException
         */
        public static function getStorageInfo($path, $rootInfo = null, $includeMountPoints = true, $useCache = true) {
@@ -491,8 +504,9 @@ class OC_Helper {
                }
                $used = $rootInfo->getSize($includeMountPoints);
                if ($used < 0) {
-                       $used = 0;
+                       $used = 0.0;
                }
+               /** @var int|float $quota */
                $quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
                $mount = $rootInfo->getMountPoint();
                $storage = $mount->getStorage();
@@ -523,6 +537,9 @@ class OC_Helper {
                }
                try {
                        $free = $sourceStorage->free_space($rootInfo->getInternalPath());
+                       if (is_bool($free)) {
+                               $free = 0.0;
+                       }
                } catch (\Exception $e) {
                        if ($path === "") {
                                throw $e;
@@ -549,6 +566,7 @@ class OC_Helper {
                        $relative = 0;
                }
 
+               /** @var string $ownerId */
                $ownerId = $storage->getOwner($path);
                $ownerDisplayName = '';
                if ($ownerId) {
@@ -580,15 +598,20 @@ class OC_Helper {
 
        /**
         * Get storage info including all mount points and quota
+        *
+        * @psalm-suppress LessSpecificReturnStatement Legacy code outputs weird types - manually validated that they are correct
+        * @return StorageInfo
         */
        private static function getGlobalStorageInfo(int|float $quota, IUser $user, IMountPoint $mount): array {
                $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
+               /** @var int|float $used */
                $used = $rootInfo['size'];
                if ($used < 0) {
-                       $used = 0;
+                       $used = 0.0;
                }
 
                $total = $quota;
+               /** @var int|float $free */
                $free = $quota - $used;
 
                if ($total > 0) {
@@ -598,7 +621,7 @@ class OC_Helper {
                        // prevent division by zero or error codes (negative values)
                        $relative = round(($used / $total) * 10000) / 100;
                } else {
-                       $relative = 0;
+                       $relative = 0.0;
                }
 
                if (substr_count($mount->getMountPoint(), '/') < 3) {
index 7ab70fb04bfb48446d9663075e62a157423898d4..cf387a8a44ccc0c6ffddb06b95398f68f4fe0099 100644 (file)
@@ -62,7 +62,7 @@ interface IAppConfig {
 
        /**
         * Get all apps using the config
-        * @return array an array of app ids
+        * @return string[] an array of app ids
         *
         * This function returns a list of all apps that have at least one
         * entry in the appconfig table.