Skip to content

Commit bc533b8

Browse files
committed
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>
1 parent 5512c24 commit bc533b8

4 files changed

Lines changed: 88 additions & 10 deletions

File tree

apps/provisioning_api/lib/Controller/AUserData.php

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
use OCP\User\Backend\ISetPasswordBackend;
5252

5353
abstract class AUserData extends OCSController {
54+
public const SCOPE_SUFFIX = 'Scope';
5455

5556
/** @var IUserManager */
5657
protected $userManager;
@@ -87,12 +88,13 @@ public function __construct(string $appName,
8788
* creates a array with all user data
8889
*
8990
* @param string $userId
91+
* @param bool $includeScopes
9092
* @return array
9193
* @throws NotFoundException
9294
* @throws OCSException
9395
* @throws OCSNotFoundException
9496
*/
95-
protected function getUserData(string $userId): array {
97+
protected function getUserData(string $userId, bool $includeScopes = false): array {
9698
$currentLoggedInUser = $this->userSession->getUser();
9799

98100
$data = [];
@@ -115,7 +117,7 @@ protected function getUserData(string $userId): array {
115117
}
116118

117119
// Get groups data
118-
$userAccount = $this->accountManager->getUser($targetUserObject);
120+
$userAccount = $this->accountManager->getAccount($targetUserObject);
119121
$groups = $this->groupManager->getUserGroups($targetUserObject);
120122
$gids = [];
121123
foreach ($groups as $group) {
@@ -138,11 +140,26 @@ protected function getUserData(string $userId): array {
138140
$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
139141
$data['quota'] = $this->fillStorageInfo($targetUserObject->getUID());
140142
$data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getEMailAddress();
143+
if ($includeScopes) {
144+
$data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
145+
}
141146
$data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
142-
$data[IAccountManager::PROPERTY_PHONE] = $userAccount[IAccountManager::PROPERTY_PHONE]['value'];
143-
$data[IAccountManager::PROPERTY_ADDRESS] = $userAccount[IAccountManager::PROPERTY_ADDRESS]['value'];
144-
$data[IAccountManager::PROPERTY_WEBSITE] = $userAccount[IAccountManager::PROPERTY_WEBSITE]['value'];
145-
$data[IAccountManager::PROPERTY_TWITTER] = $userAccount[IAccountManager::PROPERTY_TWITTER]['value'];
147+
if ($includeScopes) {
148+
$data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
149+
}
150+
151+
foreach ([
152+
IAccountManager::PROPERTY_PHONE,
153+
IAccountManager::PROPERTY_ADDRESS,
154+
IAccountManager::PROPERTY_WEBSITE,
155+
IAccountManager::PROPERTY_TWITTER,
156+
] as $propertyName) {
157+
$property = $userAccount->getProperty($propertyName);
158+
$data[$propertyName] = $property->getValue();
159+
if ($includeScopes) {
160+
$data[$propertyName . self::SCOPE_SUFFIX] = $property->getScope();
161+
}
162+
}
146163
$data['groups'] = $gids;
147164
$data['language'] = $this->l10nFactory->getUserLanguage($targetUserObject);
148165
$data['locale'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');

apps/provisioning_api/lib/Controller/UsersController.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,13 @@ public function addUser(string $userid,
483483
* @throws OCSException
484484
*/
485485
public function getUser(string $userId): DataResponse {
486-
$data = $this->getUserData($userId);
486+
$includeScopes = false;
487+
$currentUser = $this->userSession->getUser();
488+
if ($currentUser && $currentUser->getUID() === $userId) {
489+
$includeScopes = true;
490+
}
491+
492+
$data = $this->getUserData($userId, $includeScopes);
487493
// getUserData returns empty array if not enough permissions
488494
if (empty($data)) {
489495
throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
@@ -503,7 +509,7 @@ public function getUser(string $userId): DataResponse {
503509
public function getCurrentUser(): DataResponse {
504510
$user = $this->userSession->getUser();
505511
if ($user) {
506-
$data = $this->getUserData($user->getUID());
512+
$data = $this->getUserData($user->getUID(), true);
507513
// rename "displayname" to "display-name" only for this call to keep
508514
// the API stable.
509515
$data['display-name'] = $data['displayname'];
@@ -565,6 +571,9 @@ public function editUser(string $userId, string $key, string $value): DataRespon
565571
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
566572
}
567573

574+
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
575+
$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
576+
568577
$permittedFields[] = 'password';
569578
if ($this->config->getSystemValue('force_language', false) === false ||
570579
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
@@ -580,6 +589,10 @@ public function editUser(string $userId, string $key, string $value): DataRespon
580589
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
581590
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
582591
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
592+
$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
593+
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
594+
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
595+
$permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
583596

584597
// If admin they can edit their own quota
585598
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
@@ -684,6 +697,23 @@ public function editUser(string $userId, string $key, string $value): DataRespon
684697
}
685698
}
686699
break;
700+
case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
701+
case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
702+
case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
703+
case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
704+
case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
705+
case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
706+
$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
707+
$userAccount = $this->accountManager->getUser($targetUser);
708+
if ($userAccount[$propertyName]['scope'] !== $value) {
709+
$userAccount[$propertyName]['scope'] = $value;
710+
try {
711+
$this->accountManager->updateUser($targetUser, $userAccount, true);
712+
} catch (\InvalidArgumentException $e) {
713+
throw new OCSException('Invalid ' . $e->getMessage(), 102);
714+
}
715+
}
716+
break;
687717
default:
688718
throw new OCSException('', 103);
689719
}

lib/private/Accounts/AccountManager.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,37 @@ public function updateUser(IUser $user, array $data, bool $throwOnData = false):
144144
}
145145
}
146146

147+
$allowedScopes = [
148+
self::SCOPE_PRIVATE,
149+
self::SCOPE_LOCAL,
150+
self::SCOPE_FEDERATED,
151+
self::SCOPE_PUBLISHED,
152+
self::VISIBILITY_PRIVATE,
153+
self::VISIBILITY_CONTACTS_ONLY,
154+
self::VISIBILITY_PUBLIC,
155+
];
156+
157+
// validate and convert scope values
158+
foreach ($data as $propertyName => $propertyData) {
159+
if (isset($propertyData['scope'])) {
160+
if ($throwOnData && !in_array($propertyData['scope'], $allowedScopes, true)) {
161+
throw new \InvalidArgumentException('scope');
162+
}
163+
164+
if (
165+
$propertyData['scope'] === self::SCOPE_PRIVATE
166+
&& ($propertyName === self::PROPERTY_DISPLAYNAME || $propertyName === self::PROPERTY_EMAIL)
167+
) {
168+
// v2-private is not available for these fields
169+
throw new \InvalidArgumentException('scope');
170+
}
171+
172+
// migrate scope values to the new format
173+
// invalid scopes are mapped to a default value
174+
$data[$propertyName]['scope'] = AccountProperty::mapScopeToV2($propertyData['scope']);
175+
}
176+
}
177+
147178
if (empty($userData)) {
148179
$this->insertNewUser($user, $data);
149180
} elseif ($userData !== $data) {
@@ -405,7 +436,7 @@ protected function writeUserData(IUser $user, array $data): void {
405436
}
406437

407438
$query->setParameter('name', $propertyName)
408-
->setParameter('value', $property['value']);
439+
->setParameter('value', $property['value'] ?? '');
409440
$query->execute();
410441
}
411442
}

lib/private/Accounts/AccountProperty.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public function getScope(): string {
128128
return $this->scope;
129129
}
130130

131-
private function mapScopeToV2($scope) {
131+
public static function mapScopeToV2($scope) {
132132
if (strpos($scope, 'v2-') === 0) {
133133
return $scope;
134134
}

0 commit comments

Comments
 (0)