'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',
);
'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)
* @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
*
/**
* 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');
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;
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';
*
* @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');
} else {
// Check they are looking up themselves
if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
- return $data;
+ return null;
}
}
* Get the groups a user is a subadmin of
*
* @param string $userId
- * @return array
+ * @return string[]
* @throws OCSException
*/
protected function getUserSubAdminGroupsData(string $userId): array {
/**
* @param string $userId
- * @return array
+ * @return ProvisioningApiUserDetailsQuota
* @throws OCSException
*/
protected function fillStorageInfo(string $userId): array {
*
* @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
*
}
/**
- * @return DataResponse
+ * Get a list of apps
+ *
+ * @return DataResponse<Http::STATUS_OK, array{data: string[]}, array{}>
*/
public function getApps(): DataResponse {
return new DataResponse([
}
/**
- * @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 {
}
/**
- * @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 {
* @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();
/**
* @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 {
* @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
*
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;
}
/**
- * @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':
}
/**
- * @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 {
/**
* @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 {
/**
* @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);
* @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
*
*/
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;
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 */
}
/**
- * 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 */
}
/**
- * 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);
/**
* @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
}
/**
- * 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);
/** @var IUser $user */
return $user->getUID();
}, $users);
+ /** @var string[] $users */
$users = array_values($users);
return new DataResponse(['users' => $users]);
}
}
/**
- * 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 {
$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
}
/**
- * 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 {
/**
* @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 {
/**
* @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 {
}
/**
- * @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 {
/** @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();
* @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
*
/**
* @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();
/**
* @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();
/**
* @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();
/**
* @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();
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;
use OCP\User\Backend\ISetDisplayNameBackend;
use Psr\Log\LoggerInterface;
+/**
+ * @psalm-import-type ProvisioningApiUserDetails from ResponseDefinitions
+ */
class UsersController extends AUserData {
/** @var IURLGenerator */
protected $urlGenerator;
/**
* @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();
}
}
+ /** @var string[] $users */
$users = array_keys($users);
return new DataResponse([
/**
* @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();
$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
* @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();
* @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,
* @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 {
}
$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);
* @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);
}
* @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 {
* @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 {
* @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(
* @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 {
* @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
*/
* @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 {
* @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);
* @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);
/**
* @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 {
* @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 {
foreach ($getSubAdminsGroups as $key => $group) {
$getSubAdminsGroups[$key] = $group->getGID();
}
+ /** @var string[] $groups */
$groups = array_intersect(
$getSubAdminsGroups,
$this->groupManager->getUserGroupIds($targetUser)
* @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 {
* @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 {
}
/**
- * 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 {
}
/**
- * 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 {
/**
* 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 {
* @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 {
* @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
*
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;
use OCP\Security\VerificationToken\InvalidTokenException;
use OCP\Security\VerificationToken\IVerificationToken;
+#[IgnoreOpenAPI]
class VerificationController extends Controller {
/** @var IVerificationToken */
--- /dev/null
+<?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 {
+}
"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": {}
}
}
}
/**
* 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.
/**
* 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;
* @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) {
}
$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();
}
try {
$free = $sourceStorage->free_space($rootInfo->getInternalPath());
+ if (is_bool($free)) {
+ $free = 0.0;
+ }
} catch (\Exception $e) {
if ($path === "") {
throw $e;
$relative = 0;
}
+ /** @var string $ownerId */
$ownerId = $storage->getOwner($path);
$ownerDisplayName = '';
if ($ownerId) {
/**
* 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) {
// 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) {
/**
* 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.