mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
prov api to be able to edit multivalue properties
- adding as usual - deleting and scope setting via additional endpoint Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
This commit is contained in:
parent
3da9064f9d
commit
d109d4f581
6 changed files with 240 additions and 4 deletions
|
|
@ -54,6 +54,7 @@ return [
|
|||
['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)]']],
|
||||
['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'],
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ use OC\KnownUser\KnownUserService;
|
|||
use OC\User\Backend;
|
||||
use OCA\Settings\Mailer\NewUserMailHelper;
|
||||
use OCP\Accounts\IAccountManager;
|
||||
use OCP\Accounts\IAccountProperty;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
|
|
@ -601,6 +602,85 @@ class UsersController extends AUserData {
|
|||
return new DataResponse($permittedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 !== '') {
|
||||
// "replace on"
|
||||
$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() === $value) {
|
||||
$targetProperty = $property;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($targetProperty instanceof IAccountProperty) {
|
||||
$targetProperty->setScope($value);
|
||||
$this->accountManager->updateAccount($userAccount);
|
||||
} else {
|
||||
throw new OCSException('', 102);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new OCSException('', 103);
|
||||
}
|
||||
return new DataResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoSubAdminRequired
|
||||
|
|
@ -637,6 +717,8 @@ class UsersController extends AUserData {
|
|||
$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())) {
|
||||
|
|
@ -675,6 +757,7 @@ class UsersController extends AUserData {
|
|||
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
|
||||
}
|
||||
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
|
||||
$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
|
||||
$permittedFields[] = 'password';
|
||||
$permittedFields[] = 'language';
|
||||
$permittedFields[] = 'locale';
|
||||
|
|
@ -747,6 +830,21 @@ class UsersController extends AUserData {
|
|||
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:
|
||||
|
|
|
|||
|
|
@ -169,13 +169,20 @@ trait Provisioning {
|
|||
foreach ($settings->getRows() as $setting) {
|
||||
$value = json_decode(json_encode(simplexml_load_string($response->getBody())->data->{$setting[0]}), 1);
|
||||
if (isset($value[0])) {
|
||||
Assert::assertEquals($setting[1], $value[0], "", 0.0, 10, true);
|
||||
if (in_array($setting[0], ['additional_mail', 'additional_mailScope'], true)) {
|
||||
$expectedValues = explode(';', $setting[1]);
|
||||
foreach ($expectedValues as $expected) {
|
||||
Assert::assertTrue(in_array($expected, $value, true));
|
||||
}
|
||||
} else {
|
||||
Assert::assertEquals($setting[1], $value[0], "", 0.0, 10, true);
|
||||
}
|
||||
} else {
|
||||
Assert::assertEquals('', $setting[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Then /^group "([^"]*)" has$/
|
||||
*
|
||||
|
|
@ -194,7 +201,7 @@ trait Provisioning {
|
|||
$options['headers'] = [
|
||||
'OCS-APIREQUEST' => 'true',
|
||||
];
|
||||
|
||||
|
||||
$response = $client->get($fullUrl, $options);
|
||||
$groupDetails = simplexml_load_string($response->getBody())->data[0]->groups[0]->element;
|
||||
foreach ($settings->getRows() as $setting) {
|
||||
|
|
@ -206,7 +213,7 @@ trait Provisioning {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @Then /^user "([^"]*)" has editable fields$/
|
||||
|
|
@ -967,4 +974,38 @@ trait Provisioning {
|
|||
}
|
||||
$this->usingServer($previousServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^user "([^"]*)" has not$/
|
||||
*/
|
||||
public function userHasNotSetting($user, \Behat\Gherkin\Node\TableNode $settings) {
|
||||
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user";
|
||||
$client = new Client();
|
||||
$options = [];
|
||||
if ($this->currentUser === 'admin') {
|
||||
$options['auth'] = $this->adminUser;
|
||||
} else {
|
||||
$options['auth'] = [$this->currentUser, $this->regularUser];
|
||||
}
|
||||
$options['headers'] = [
|
||||
'OCS-APIREQUEST' => 'true',
|
||||
];
|
||||
|
||||
$response = $client->get($fullUrl, $options);
|
||||
foreach ($settings->getRows() as $setting) {
|
||||
$value = json_decode(json_encode(simplexml_load_string($response->getBody())->data->{$setting[0]}), 1);
|
||||
if (isset($value[0])) {
|
||||
if (in_array($setting[0], ['additional_mail', 'additional_mailScope'], true)) {
|
||||
$expectedValues = explode(';', $setting[1]);
|
||||
foreach ($expectedValues as $expected) {
|
||||
Assert::assertFalse(in_array($expected, $value, true));
|
||||
}
|
||||
} else {
|
||||
Assert::assertNotEquals($setting[1], $value[0], "", 0.0, 10, true);
|
||||
}
|
||||
} else {
|
||||
Assert::assertNotEquals('', $setting[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,16 @@ Feature: provisioning
|
|||
| value | no-reply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | no.reply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | noreply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | phone |
|
||||
| value | +49 711 / 25 24 28-90 |
|
||||
|
|
@ -127,6 +137,7 @@ Feature: provisioning
|
|||
| id | brand-new-user |
|
||||
| displayname | Brand New User |
|
||||
| email | no-reply@nextcloud.com |
|
||||
| additional_mail | no.reply@nextcloud.com;noreply@nextcloud.com |
|
||||
| phone | +4971125242890 |
|
||||
| address | Foo Bar Town |
|
||||
| website | https://nextcloud.com |
|
||||
|
|
@ -180,6 +191,33 @@ Feature: provisioning
|
|||
| displaynameScope | v2-federated |
|
||||
| avatarScope | v2-local |
|
||||
|
||||
Scenario: Edit a user account multivalue property scopes
|
||||
Given user "brand-new-user" exists
|
||||
And As an "brand-new-user"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | no.reply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | noreply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user/additional_mailScope" with
|
||||
| key | no.reply@nextcloud.com |
|
||||
| value | v2-federated |
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user/additional_mailScope" with
|
||||
| key | noreply@nextcloud.com |
|
||||
| value | v2-published |
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
Then user "brand-new-user" has
|
||||
| id | brand-new-user |
|
||||
| additional_mailScope | v2-federated;v2-published |
|
||||
|
||||
Scenario: Edit a user account properties scopes with invalid or unsupported value
|
||||
Given user "brand-new-user" exists
|
||||
And As an "brand-new-user"
|
||||
|
|
@ -199,6 +237,43 @@ Feature: provisioning
|
|||
Then the OCS status code should be "102"
|
||||
And the HTTP status code should be "200"
|
||||
|
||||
Scenario: Edit a user account multi-value property scopes with invalid or unsupported value
|
||||
Given user "brand-new-user" exists
|
||||
And As an "brand-new-user"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | no.reply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user/additional_mailScope" with
|
||||
| key | no.reply@nextcloud.com |
|
||||
| value | invalid |
|
||||
Then the OCS status code should be "102"
|
||||
And the HTTP status code should be "200"
|
||||
|
||||
Scenario: Delete a user account multi-value property value
|
||||
Given user "brand-new-user" exists
|
||||
And As an "brand-new-user"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | no.reply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "PUT" to "/cloud/users/brand-new-user" with
|
||||
| key | additional_mail |
|
||||
| value | noreply@nextcloud.com |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
When sending "PUT" to "/cloud/users/brand-new-user/additional_mail" with
|
||||
| key | no.reply@nextcloud.com |
|
||||
| value | |
|
||||
And the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
Then user "brand-new-user" has
|
||||
| additional_mail | noreply@nextcloud.com |
|
||||
Then user "brand-new-user" has not
|
||||
| additional_mail | no.reply@nextcloud.com |
|
||||
|
||||
Scenario: An admin cannot edit user account property scopes
|
||||
Given As an "admin"
|
||||
And user "brand-new-user" exists
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ declare(strict_types=1);
|
|||
namespace OC\Accounts;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OCP\Accounts\IAccountManager;
|
||||
use OCP\Accounts\IAccountProperty;
|
||||
use OCP\Accounts\IAccountPropertyCollection;
|
||||
|
||||
|
|
@ -63,6 +64,18 @@ class AccountPropertyCollection implements IAccountPropertyCollection {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function addPropertyWithDefaults(string $value): IAccountPropertyCollection {
|
||||
$property = new AccountProperty(
|
||||
$this->collectionName,
|
||||
$value,
|
||||
IAccountManager::SCOPE_LOCAL,
|
||||
IAccountManager::NOT_VERIFIED,
|
||||
''
|
||||
);
|
||||
$this->addProperty($property);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeProperty(IAccountProperty $property): IAccountPropertyCollection {
|
||||
$ref = array_search($property, $this->properties, true);
|
||||
if ($ref !== false) {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,14 @@ interface IAccountPropertyCollection extends JsonSerializable {
|
|||
*/
|
||||
public function addProperty(IAccountProperty $property): IAccountPropertyCollection;
|
||||
|
||||
/**
|
||||
* adds a property to this collection with only specifying the value
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @since 22.0.0
|
||||
*/
|
||||
public function addPropertyWithDefaults(string $value): IAccountPropertyCollection;
|
||||
|
||||
/**
|
||||
* removes a property of this collection
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue