Skip to content

Commit

Permalink
Merge pull request #27474 from nextcloud/feat/26866/prov-api
Browse files Browse the repository at this point in the history
  • Loading branch information
skjnldsv authored Jun 30, 2021
2 parents 62ff4fe + ad0a11b commit 9124c69
Show file tree
Hide file tree
Showing 16 changed files with 844 additions and 645 deletions.
1 change: 1 addition & 0 deletions apps/provisioning_api/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
['root' => '/cloud', 'name' => 'Users#getEditableFields', 'url' => '/user/fields', 'verb' => 'GET'],
['root' => '/cloud', 'name' => 'Users#getEditableFieldsForUser', 'url' => '/user/fields/{userId}', 'verb' => 'GET'],
['root' => '/cloud', 'name' => 'Users#editUser', 'url' => '/users/{userId}', 'verb' => 'PUT'],
['root' => '/cloud', 'name' => 'Users#editUserMultiValue', 'url' => '/users/{userId}/{collectionName}', 'verb' => 'PUT', 'requirements' => ['collectionName' => '^(?!enable$|disable$)[a-zA-Z0-0_]*$']],
['root' => '/cloud', 'name' => 'Users#wipeUserDevices', 'url' => '/users/{userId}/wipe', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#deleteUser', 'url' => '/users/{userId}', 'verb' => 'DELETE'],
['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'],
Expand Down
14 changes: 14 additions & 0 deletions apps/provisioning_api/lib/Controller/AUserData.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,20 @@ protected function getUserData(string $userId, bool $includeScopes = false): arr
if ($includeScopes) {
$data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
}

$additionalEmails = $additionalEmailScopes = [];
$emailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
foreach ($emailCollection->getProperties() as $property) {
$additionalEmails[] = $property->getValue();
if ($includeScopes) {
$additionalEmailScopes[] = $property->getScope();
}
}
$data[IAccountManager::COLLECTION_EMAIL] = $additionalEmails;
if ($includeScopes) {
$data[IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX] = $additionalEmailScopes;
}

$data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
if ($includeScopes) {
$data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
Expand Down
135 changes: 120 additions & 15 deletions apps/provisioning_api/lib/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
use OC\User\Backend;
use OCA\Settings\Mailer\NewUserMailHelper;
use OCP\Accounts\IAccountManager;
use OCP\App\IAppManager;
use OCP\Accounts\IAccountProperty;
use OCP\Accounts\PropertyDoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
Expand All @@ -75,8 +76,6 @@

class UsersController extends AUserData {

/** @var IAppManager */
private $appManager;
/** @var IURLGenerator */
protected $urlGenerator;
/** @var LoggerInterface */
Expand All @@ -98,7 +97,6 @@ public function __construct(string $appName,
IRequest $request,
IUserManager $userManager,
IConfig $config,
IAppManager $appManager,
IGroupManager $groupManager,
IUserSession $userSession,
IAccountManager $accountManager,
Expand All @@ -119,7 +117,6 @@ public function __construct(string $appName,
$accountManager,
$l10nFactory);

$this->appManager = $appManager;
$this->urlGenerator = $urlGenerator;
$this->logger = $logger;
$this->l10nFactory = $l10nFactory;
Expand Down Expand Up @@ -592,6 +589,7 @@ public function getEditableFieldsForUser(string $userId): DataResponse {
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
}

$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
$permittedFields[] = IAccountManager::PROPERTY_PHONE;
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
Expand All @@ -600,6 +598,92 @@ public function getEditableFieldsForUser(string $userId): DataResponse {
return new DataResponse($permittedFields);
}

/**
* @NoAdminRequired
* @NoSubAdminRequired
* @PasswordConfirmationRequired
*
* @throws OCSException
*/
public function editUserMultiValue(
string $userId,
string $collectionName,
string $key,
string $value
): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();
if ($currentLoggedInUser === null) {
throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
}

$targetUser = $this->userManager->get($userId);
if ($targetUser === null) {
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}

$permittedFields = [];
if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
// Editing self (display, email)
$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
$permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
} else {
// Check if admin / subadmin
$subAdminManager = $this->groupManager->getSubAdmin();
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
// They have permissions over the user

$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
} else {
// No rights
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
}

// Check if permitted to edit this field
if (!in_array($collectionName, $permittedFields)) {
throw new OCSException('', 103);
}

switch ($collectionName) {
case IAccountManager::COLLECTION_EMAIL:
$userAccount = $this->accountManager->getAccount($targetUser);
$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
$mailCollection->removePropertyByValue($key);
if ($value !== '') {
$mailCollection->addPropertyWithDefaults($value);
}
$this->accountManager->updateAccount($userAccount);
break;

case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
$userAccount = $this->accountManager->getAccount($targetUser);
$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
$targetProperty = null;
foreach ($mailCollection->getProperties() as $property) {
if ($property->getValue() === $key) {
$targetProperty = $property;
break;
}
}
if ($targetProperty instanceof IAccountProperty) {
try {
$targetProperty->setScope($value);
$this->accountManager->updateAccount($userAccount);
} catch (\InvalidArgumentException $e) {
throw new OCSException('', 102);
}
} else {
throw new OCSException('', 102);
}
break;

default:
throw new OCSException('', 103);
}
return new DataResponse();
}

/**
* @NoAdminRequired
* @NoSubAdminRequired
Expand Down Expand Up @@ -636,6 +720,8 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;

$permittedFields[] = IAccountManager::COLLECTION_EMAIL;

$permittedFields[] = 'password';
if ($this->config->getSystemValue('force_language', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
Expand Down Expand Up @@ -674,6 +760,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
$permittedFields[] = 'password';
$permittedFields[] = 'language';
$permittedFields[] = 'locale';
Expand Down Expand Up @@ -746,24 +833,42 @@ public function editUser(string $userId, string $key, string $value): DataRespon
throw new OCSException('', 102);
}
break;
case IAccountManager::COLLECTION_EMAIL:
if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getEMailAddress()) {
$userAccount = $this->accountManager->getAccount($targetUser);
$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
foreach ($mailCollection->getProperties() as $property) {
if ($property->getValue() === $value) {
break;
}
}
$mailCollection->addPropertyWithDefaults($value);
$this->accountManager->updateAccount($userAccount);
} else {
throw new OCSException('', 102);
}
break;
case IAccountManager::PROPERTY_PHONE:
case IAccountManager::PROPERTY_ADDRESS:
case IAccountManager::PROPERTY_WEBSITE:
case IAccountManager::PROPERTY_TWITTER:
$userAccount = $this->accountManager->getAccount($targetUser);
$userProperty = $userAccount->getProperty($key);
if ($userProperty->getValue() !== $value) {
try {
$userProperty->setValue($value);
$this->accountManager->updateAccount($userAccount);

if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
$this->knownUserService->deleteByContactUserId($targetUser->getUID());
try {
$userProperty = $userAccount->getProperty($key);
if ($userProperty->getValue() !== $value) {
try {
$userProperty->setValue($value);
if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
$this->knownUserService->deleteByContactUserId($targetUser->getUID());
}
} catch (\InvalidArgumentException $e) {
throw new OCSException('Invalid ' . $e->getMessage(), 102);
}
} catch (\InvalidArgumentException $e) {
throw new OCSException('Invalid ' . $e->getMessage(), 102);
}
} catch (PropertyDoesNotExistException $e) {
$userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
}
$this->accountManager->updateAccount($userAccount);
break;
case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
Expand Down
20 changes: 9 additions & 11 deletions apps/provisioning_api/tests/Controller/UsersControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
use OCP\Accounts\IAccount;
use OCP\Accounts\IAccountManager;
use OCP\Accounts\IAccountProperty;
use OCP\App\IAppManager;
use OCP\AppFramework\Http\DataResponse;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
Expand All @@ -77,8 +76,6 @@ class UsersControllerTest extends TestCase {
protected $userManager;
/** @var IConfig|MockObject */
protected $config;
/** @var IAppManager|MockObject */
protected $appManager;
/** @var Manager|MockObject */
protected $groupManager;
/** @var IUserSession|MockObject */
Expand Down Expand Up @@ -111,7 +108,6 @@ protected function setUp(): void {

$this->userManager = $this->createMock(IUserManager::class);
$this->config = $this->createMock(IConfig::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->groupManager = $this->createMock(Manager::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->logger = $this->createMock(LoggerInterface::class);
Expand All @@ -131,7 +127,6 @@ protected function setUp(): void {
$this->request,
$this->userManager,
$this->config,
$this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
Expand Down Expand Up @@ -395,7 +390,6 @@ public function testAddUserSuccessfulWithDisplayName() {
$this->request,
$this->userManager,
$this->config,
$this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
Expand Down Expand Up @@ -1071,7 +1065,8 @@ public function testGetUserDataAsAdmin() {
'backendCapabilities' => [
'setDisplayName' => true,
'setPassword' => true,
]
],
'additional_mail' => [],
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
Expand Down Expand Up @@ -1198,7 +1193,8 @@ public function testGetUserDataAsSubAdminAndUserIsAccessible() {
'backendCapabilities' => [
'setDisplayName' => true,
'setPassword' => true,
]
],
'additional_mail' => [],
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
Expand Down Expand Up @@ -1363,7 +1359,8 @@ public function testGetUserDataAsSubAdminSelfLookup() {
'backendCapabilities' => [
'setDisplayName' => false,
'setPassword' => false,
]
],
'additional_mail' => [],
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
Expand Down Expand Up @@ -3437,7 +3434,6 @@ public function testGetCurrentUserLoggedIn() {
$this->request,
$this->userManager,
$this->config,
$this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
Expand Down Expand Up @@ -3510,7 +3506,6 @@ public function testGetUser() {
$this->request,
$this->userManager,
$this->config,
$this->appManager,
$this->groupManager,
$this->userSession,
$this->accountManager,
Expand Down Expand Up @@ -3848,6 +3843,7 @@ public function testResendWelcomeMessageFailed() {
public function dataGetEditableFields() {
return [
[false, ISetDisplayNameBackend::class, [
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
Expand All @@ -3856,13 +3852,15 @@ public function dataGetEditableFields() {
[true, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_DISPLAYNAME,
IAccountManager::PROPERTY_EMAIL,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
]],
[true, UserInterface::class, [
IAccountManager::PROPERTY_EMAIL,
IAccountManager::COLLECTION_EMAIL,
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
Expand Down
Loading

0 comments on commit 9124c69

Please sign in to comment.