OCS allow reading and writing account property scopes
Extends the provisioning API to allow a user to get and set their own account property scopes. Signed-off-by: Vincent Petry <vincent@nextcloud.com>
This commit is contained in:
parent
5c854ba132
commit
b9d59e2994
|
@ -50,6 +50,7 @@ use OCP\User\Backend\ISetDisplayNameBackend;
|
||||||
use OCP\User\Backend\ISetPasswordBackend;
|
use OCP\User\Backend\ISetPasswordBackend;
|
||||||
|
|
||||||
abstract class AUserData extends OCSController {
|
abstract class AUserData extends OCSController {
|
||||||
|
public const SCOPE_SUFFIX = 'Scope';
|
||||||
|
|
||||||
/** @var IUserManager */
|
/** @var IUserManager */
|
||||||
protected $userManager;
|
protected $userManager;
|
||||||
|
@ -86,12 +87,13 @@ abstract class AUserData extends OCSController {
|
||||||
* creates a array with all user data
|
* creates a array with all user data
|
||||||
*
|
*
|
||||||
* @param string $userId
|
* @param string $userId
|
||||||
|
* @param bool $includeScopes
|
||||||
* @return array
|
* @return array
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @throws OCSException
|
* @throws OCSException
|
||||||
* @throws OCSNotFoundException
|
* @throws OCSNotFoundException
|
||||||
*/
|
*/
|
||||||
protected function getUserData(string $userId): array {
|
protected function getUserData(string $userId, bool $includeScopes = false): array {
|
||||||
$currentLoggedInUser = $this->userSession->getUser();
|
$currentLoggedInUser = $this->userSession->getUser();
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
@ -114,7 +116,7 @@ abstract class AUserData extends OCSController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get groups data
|
// Get groups data
|
||||||
$userAccount = $this->accountManager->getUser($targetUserObject);
|
$userAccount = $this->accountManager->getAccount($targetUserObject);
|
||||||
$groups = $this->groupManager->getUserGroups($targetUserObject);
|
$groups = $this->groupManager->getUserGroups($targetUserObject);
|
||||||
$gids = [];
|
$gids = [];
|
||||||
foreach ($groups as $group) {
|
foreach ($groups as $group) {
|
||||||
|
@ -137,11 +139,26 @@ abstract class AUserData extends OCSController {
|
||||||
$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
|
$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
|
||||||
$data['quota'] = $this->fillStorageInfo($targetUserObject->getUID());
|
$data['quota'] = $this->fillStorageInfo($targetUserObject->getUID());
|
||||||
$data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getEMailAddress();
|
$data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getEMailAddress();
|
||||||
|
if ($includeScopes) {
|
||||||
|
$data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
|
||||||
|
}
|
||||||
$data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
|
$data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
|
||||||
$data[IAccountManager::PROPERTY_PHONE] = $userAccount[IAccountManager::PROPERTY_PHONE]['value'];
|
if ($includeScopes) {
|
||||||
$data[IAccountManager::PROPERTY_ADDRESS] = $userAccount[IAccountManager::PROPERTY_ADDRESS]['value'];
|
$data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
|
||||||
$data[IAccountManager::PROPERTY_WEBSITE] = $userAccount[IAccountManager::PROPERTY_WEBSITE]['value'];
|
}
|
||||||
$data[IAccountManager::PROPERTY_TWITTER] = $userAccount[IAccountManager::PROPERTY_TWITTER]['value'];
|
|
||||||
|
foreach ([
|
||||||
|
IAccountManager::PROPERTY_PHONE,
|
||||||
|
IAccountManager::PROPERTY_ADDRESS,
|
||||||
|
IAccountManager::PROPERTY_WEBSITE,
|
||||||
|
IAccountManager::PROPERTY_TWITTER,
|
||||||
|
] as $propertyName) {
|
||||||
|
$property = $userAccount->getProperty($propertyName);
|
||||||
|
$data[$propertyName] = $property->getValue();
|
||||||
|
if ($includeScopes) {
|
||||||
|
$data[$propertyName . self::SCOPE_SUFFIX] = $property->getScope();
|
||||||
|
}
|
||||||
|
}
|
||||||
$data['groups'] = $gids;
|
$data['groups'] = $gids;
|
||||||
$data['language'] = $this->l10nFactory->getUserLanguage($targetUserObject);
|
$data['language'] = $this->l10nFactory->getUserLanguage($targetUserObject);
|
||||||
$data['locale'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
|
$data['locale'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
|
||||||
|
|
|
@ -470,7 +470,13 @@ class UsersController extends AUserData {
|
||||||
* @throws OCSException
|
* @throws OCSException
|
||||||
*/
|
*/
|
||||||
public function getUser(string $userId): DataResponse {
|
public function getUser(string $userId): DataResponse {
|
||||||
$data = $this->getUserData($userId);
|
$includeScopes = false;
|
||||||
|
$currentUser = $this->userSession->getUser();
|
||||||
|
if ($currentUser && $currentUser->getUID() === $userId) {
|
||||||
|
$includeScopes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->getUserData($userId, $includeScopes);
|
||||||
// getUserData returns empty array if not enough permissions
|
// getUserData returns empty array if not enough permissions
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
|
throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
|
||||||
|
@ -490,7 +496,7 @@ class UsersController extends AUserData {
|
||||||
public function getCurrentUser(): DataResponse {
|
public function getCurrentUser(): DataResponse {
|
||||||
$user = $this->userSession->getUser();
|
$user = $this->userSession->getUser();
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$data = $this->getUserData($user->getUID());
|
$data = $this->getUserData($user->getUID(), true);
|
||||||
// rename "displayname" to "display-name" only for this call to keep
|
// rename "displayname" to "display-name" only for this call to keep
|
||||||
// the API stable.
|
// the API stable.
|
||||||
$data['display-name'] = $data['displayname'];
|
$data['display-name'] = $data['displayname'];
|
||||||
|
@ -552,6 +558,9 @@ class UsersController extends AUserData {
|
||||||
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
|
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
|
||||||
|
$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
|
||||||
|
|
||||||
$permittedFields[] = 'password';
|
$permittedFields[] = 'password';
|
||||||
if ($this->config->getSystemValue('force_language', false) === false ||
|
if ($this->config->getSystemValue('force_language', false) === false ||
|
||||||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
|
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
|
||||||
|
@ -567,6 +576,10 @@ class UsersController extends AUserData {
|
||||||
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
|
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
|
||||||
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
|
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
|
||||||
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
|
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
|
||||||
|
$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
|
||||||
|
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
|
||||||
|
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
|
||||||
|
$permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
|
||||||
|
|
||||||
// If admin they can edit their own quota
|
// If admin they can edit their own quota
|
||||||
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
|
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
|
||||||
|
@ -671,6 +684,23 @@ class UsersController extends AUserData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
|
||||||
|
case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
|
||||||
|
case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
|
||||||
|
case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
|
||||||
|
case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
|
||||||
|
case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
|
||||||
|
$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
|
||||||
|
$userAccount = $this->accountManager->getUser($targetUser);
|
||||||
|
if ($userAccount[$propertyName]['scope'] !== $value) {
|
||||||
|
$userAccount[$propertyName]['scope'] = $value;
|
||||||
|
try {
|
||||||
|
$this->accountManager->updateUser($targetUser, $userAccount, true);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
throw new OCSException('Invalid ' . $e->getMessage(), 102);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new OCSException('', 103);
|
throw new OCSException('', 103);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,37 @@ class AccountManager implements IAccountManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$allowedScopes = [
|
||||||
|
self::SCOPE_PRIVATE,
|
||||||
|
self::SCOPE_LOCAL,
|
||||||
|
self::SCOPE_FEDERATED,
|
||||||
|
self::SCOPE_PUBLISHED,
|
||||||
|
self::VISIBILITY_PRIVATE,
|
||||||
|
self::VISIBILITY_CONTACTS_ONLY,
|
||||||
|
self::VISIBILITY_PUBLIC,
|
||||||
|
];
|
||||||
|
|
||||||
|
// validate and convert scope values
|
||||||
|
foreach ($data as $propertyName => $propertyData) {
|
||||||
|
if (isset($propertyData['scope'])) {
|
||||||
|
if ($throwOnData && !in_array($propertyData['scope'], $allowedScopes, true)) {
|
||||||
|
throw new \InvalidArgumentException('scope');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$propertyData['scope'] === self::SCOPE_PRIVATE
|
||||||
|
&& ($propertyName === self::PROPERTY_DISPLAYNAME || $propertyName === self::PROPERTY_EMAIL)
|
||||||
|
) {
|
||||||
|
// v2-private is not available for these fields
|
||||||
|
throw new \InvalidArgumentException('scope');
|
||||||
|
}
|
||||||
|
|
||||||
|
// migrate scope values to the new format
|
||||||
|
// invalid scopes are mapped to a default value
|
||||||
|
$data[$propertyName]['scope'] = AccountProperty::mapScopeToV2($propertyData['scope']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($userData)) {
|
if (empty($userData)) {
|
||||||
$this->insertNewUser($user, $data);
|
$this->insertNewUser($user, $data);
|
||||||
} elseif ($userData !== $data) {
|
} elseif ($userData !== $data) {
|
||||||
|
@ -405,7 +436,7 @@ class AccountManager implements IAccountManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->setParameter('name', $propertyName)
|
$query->setParameter('name', $propertyName)
|
||||||
->setParameter('value', $property['value']);
|
->setParameter('value', $property['value'] ?? '');
|
||||||
$query->execute();
|
$query->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ class AccountProperty implements IAccountProperty {
|
||||||
return $this->scope;
|
return $this->scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function mapScopeToV2($scope) {
|
public static function mapScopeToV2($scope) {
|
||||||
if (strpos($scope, 'v2-') === 0) {
|
if (strpos($scope, 'v2-') === 0) {
|
||||||
return $scope;
|
return $scope;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue