Browse Source

Add new account properties

- New properties
  - Organisation
  - Role
  - Headline
  - Biography
  - Profile Enabled property
- Fix errors with building default account properties
- Fix L10N factory method `getLanguage` not public error
- Update tests

Signed-off-by: Christopher Ng <chrng8@gmail.com>
tags/v23.0.0beta1
Christopher Ng 2 years ago
parent
commit
7215148a24

+ 5
- 0
apps/provisioning_api/lib/Controller/AUserData.php View File

@@ -181,6 +181,11 @@ abstract class AUserData extends OCSController {
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
] as $propertyName) {
$property = $userAccount->getProperty($propertyName);
$data[$propertyName] = $property->getValue();

+ 133
- 58
apps/provisioning_api/lib/Controller/UsersController.php View File

@@ -40,6 +40,7 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\Provisioning_API\Controller;

use InvalidArgumentException;
@@ -94,29 +95,33 @@ class UsersController extends AUserData {
/** @var IEventDispatcher */
private $eventDispatcher;

public function __construct(string $appName,
IRequest $request,
IUserManager $userManager,
IConfig $config,
IGroupManager $groupManager,
IUserSession $userSession,
IAccountManager $accountManager,
IURLGenerator $urlGenerator,
LoggerInterface $logger,
IFactory $l10nFactory,
NewUserMailHelper $newUserMailHelper,
ISecureRandom $secureRandom,
RemoteWipe $remoteWipe,
KnownUserService $knownUserService,
IEventDispatcher $eventDispatcher) {
parent::__construct($appName,
$request,
$userManager,
$config,
$groupManager,
$userSession,
$accountManager,
$l10nFactory);
public function __construct(
string $appName,
IRequest $request,
IUserManager $userManager,
IConfig $config,
IGroupManager $groupManager,
IUserSession $userSession,
IAccountManager $accountManager,
IURLGenerator $urlGenerator,
LoggerInterface $logger,
IFactory $l10nFactory,
NewUserMailHelper $newUserMailHelper,
ISecureRandom $secureRandom,
RemoteWipe $remoteWipe,
KnownUserService $knownUserService,
IEventDispatcher $eventDispatcher
) {
parent::__construct(
$appName,
$request,
$userManager,
$config,
$groupManager,
$userSession,
$accountManager,
$l10nFactory
);

$this->urlGenerator = $urlGenerator;
$this->logger = $logger;
@@ -325,14 +330,16 @@ class UsersController extends AUserData {
* @return DataResponse
* @throws OCSException
*/
public function addUser(string $userid,
string $password = '',
string $displayName = '',
string $email = '',
array $groups = [],
array $subadmin = [],
string $quota = '',
string $language = ''): DataResponse {
public function addUser(
string $userid,
string $password = '',
string $displayName = '',
string $email = '',
array $groups = [],
array $subadmin = [],
string $quota = '',
string $language = ''
): DataResponse {
$user = $this->userSession->getUser();
$isAdmin = $this->groupManager->isAdmin($user->getUID());
$subAdminManager = $this->groupManager->getSubAdmin();
@@ -349,10 +356,10 @@ class UsersController extends AUserData {
if ($groups !== []) {
foreach ($groups as $group) {
if (!$this->groupManager->groupExists($group)) {
throw new OCSException('group '.$group.' does not exist', 104);
throw new OCSException('group ' . $group . ' does not exist', 104);
}
if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
throw new OCSException('insufficient privileges for group '. $group, 105);
throw new OCSException('insufficient privileges for group ' . $group, 105);
}
}
} else {
@@ -440,7 +447,8 @@ class UsersController extends AUserData {
} catch (\Exception $e) {
// Mail could be failing hard or just be plain not configured
// Logging error as it is the hardest of the two
$this->logger->error("Unable to send the invitation mail to $email",
$this->logger->error(
"Unable to send the invitation mail to $email",
[
'app' => 'ocs_api',
'exception' => $e,
@@ -452,7 +460,8 @@ class UsersController extends AUserData {

return new DataResponse(['id' => $userid]);
} catch (HintException $e) {
$this->logger->warning('Failed addUser attempt with hint exception.',
$this->logger->warning(
'Failed addUser attempt with hint exception.',
[
'app' => 'ocs_api',
'exception' => $e,
@@ -460,7 +469,8 @@ class UsersController extends AUserData {
);
throw new OCSException($e->getHint(), 107);
} catch (OCSException $e) {
$this->logger->warning('Failed addUser attempt with ocs exeption.',
$this->logger->warning(
'Failed addUser attempt with ocs exeption.',
[
'app' => 'ocs_api',
'exception' => $e,
@@ -468,7 +478,8 @@ class UsersController extends AUserData {
);
throw $e;
} catch (InvalidArgumentException $e) {
$this->logger->error('Failed addUser attempt with invalid argument exeption.',
$this->logger->error(
'Failed addUser attempt with invalid argument exeption.',
[
'app' => 'ocs_api',
'exception' => $e,
@@ -476,7 +487,8 @@ class UsersController extends AUserData {
);
throw new OCSException($e->getMessage(), 101);
} catch (\Exception $e) {
$this->logger->error('Failed addUser attempt with exception.',
$this->logger->error(
'Failed addUser attempt with exception.',
[
'app' => 'ocs_api',
'exception' => $e
@@ -573,8 +585,10 @@ class UsersController extends AUserData {
}

$subAdminManager = $this->groupManager->getSubAdmin();
if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID())
&& !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
if (
!$this->groupManager->isAdmin($currentLoggedInUser->getUID())
&& !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
) {
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
} else {
@@ -583,8 +597,10 @@ class UsersController extends AUserData {

// Editing self (display, email)
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
if (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
) {
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
@@ -595,6 +611,11 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
$permittedFields[] = IAccountManager::PROPERTY_ROLE;
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;

return new DataResponse($permittedFields);
}
@@ -700,11 +721,11 @@ class UsersController extends AUserData {
*
* @param string $userId
* @param string $key
* @param string $value
* @param string|bool $value
* @return DataResponse
* @throws OCSException
*/
public function editUser(string $userId, string $key, string $value): DataResponse {
public function editUser(string $userId, string $key, $value): DataResponse {
$currentLoggedInUser = $this->userSession->getUser();

$targetUser = $this->userManager->get($userId);
@@ -716,8 +737,10 @@ class UsersController extends AUserData {
if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
// Editing self (display, email)
if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
if (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
) {
$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
@@ -731,13 +754,17 @@ class UsersController extends AUserData {

$permittedFields[] = self::USER_FIELD_PASSWORD;
$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
if ($this->config->getSystemValue('force_language', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
if (
$this->config->getSystemValue('force_language', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())
) {
$permittedFields[] = self::USER_FIELD_LANGUAGE;
}

if ($this->config->getSystemValue('force_locale', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
if (
$this->config->getSystemValue('force_locale', false) === false ||
$this->groupManager->isAdmin($currentLoggedInUser->getUID())
) {
$permittedFields[] = self::USER_FIELD_LOCALE;
}

@@ -745,10 +772,20 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
$permittedFields[] = IAccountManager::PROPERTY_ROLE;
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
$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;
$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;

$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;

@@ -759,11 +796,15 @@ class UsersController extends AUserData {
} else {
// Check if admin / subadmin
$subAdminManager = $this->groupManager->getSubAdmin();
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
if (
$this->groupManager->isAdmin($currentLoggedInUser->getUID())
|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
) {
// They have permissions over the user
if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
if (
$targetUser->getBackend() instanceof ISetDisplayNameBackend
|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
) {
$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
}
@@ -776,6 +817,11 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
$permittedFields[] = IAccountManager::PROPERTY_ROLE;
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
$permittedFields[] = self::USER_FIELD_QUOTA;
$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
} else {
@@ -802,7 +848,7 @@ class UsersController extends AUserData {
$quota = \OCP\Util::computerFileSize($quota);
}
if ($quota === false) {
throw new OCSException('Invalid quota value '.$value, 102);
throw new OCSException('Invalid quota value ' . $value, 102);
}
if ($quota === -1) {
$quota = 'none';
@@ -892,6 +938,10 @@ class UsersController extends AUserData {
case IAccountManager::PROPERTY_ADDRESS:
case IAccountManager::PROPERTY_WEBSITE:
case IAccountManager::PROPERTY_TWITTER:
case IAccountManager::PROPERTY_ORGANISATION:
case IAccountManager::PROPERTY_ROLE:
case IAccountManager::PROPERTY_HEADLINE:
case IAccountManager::PROPERTY_BIOGRAPHY:
$userAccount = $this->accountManager->getAccount($targetUser);
try {
$userProperty = $userAccount->getProperty($key);
@@ -910,12 +960,34 @@ class UsersController extends AUserData {
}
$this->accountManager->updateAccount($userAccount);
break;
case IAccountManager::PROPERTY_PROFILE_ENABLED:
if (!is_bool($value)) {
throw new OCSException('Invalid value, value must be a boolean', 102);
}
$value = $value === true ? '1' : '0';

$userAccount = $this->accountManager->getAccount($targetUser);
try {
$userProperty = $userAccount->getProperty($key);
if ($userProperty->getValue() !== $value) {
$userProperty->setValue($value);
}
} catch (PropertyDoesNotExistException $e) {
$userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
}
$this->accountManager->updateAccount($userAccount);
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:
case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
$userAccount = $this->accountManager->getAccount($targetUser);
@@ -1300,8 +1372,10 @@ class UsersController extends AUserData {

// Check if admin / subadmin
$subAdminManager = $this->groupManager->getSubAdmin();
if (!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
&& !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
if (
!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
&& !$this->groupManager->isAdmin($currentLoggedInUser->getUID())
) {
// No rights
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}
@@ -1315,7 +1389,8 @@ class UsersController extends AUserData {
$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
} catch (\Exception $e) {
$this->logger->error("Can't send new user mail to $email",
$this->logger->error(
"Can't send new user mail to $email",
[
'app' => 'settings',
'exception' => $e,

+ 84
- 10
apps/provisioning_api/tests/Controller/UsersControllerTest.php View File

@@ -1,4 +1,5 @@
<?php

/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
@@ -38,6 +39,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\Provisioning_API\Tests\Controller;

use Exception;
@@ -165,11 +167,12 @@ class UsersControllerTest extends TestCase {
->with('MyCustomSearch')
->willReturn(['Admin' => [], 'Foo' => [], 'Bar' => []]);

$expected = ['users' => [
'Admin',
'Foo',
'Bar',
],
$expected = [
'users' => [
'Admin',
'Foo',
'Bar',
],
];
$this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
}
@@ -687,7 +690,7 @@ class UsersControllerTest extends TestCase {

$this->assertTrue(key_exists(
'id',
$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData()
$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData()
));
}

@@ -711,7 +714,8 @@ class UsersControllerTest extends TestCase {
$this->logger
->expects($this->once())
->method('error')
->with('Failed addUser attempt with exception.',
->with(
'Failed addUser attempt with exception.',
[
'app' => 'ocs_api',
'exception' => $exception
@@ -998,6 +1002,11 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
]);
$this->config
->expects($this->at(0))
@@ -1067,6 +1076,11 @@ class UsersControllerTest extends TestCase {
'setPassword' => true,
],
'additional_mail' => [],
'organisation' => 'organisation',
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1',
'notify_email' => null,
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
@@ -1166,6 +1180,11 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
]);

$this->l10nFactory
@@ -1196,6 +1215,11 @@ class UsersControllerTest extends TestCase {
'setPassword' => true,
],
'additional_mail' => [],
'organisation' => 'organisation',
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1',
'notify_email' => null,
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
@@ -1334,6 +1358,11 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
]);

$this->l10nFactory
@@ -1363,6 +1392,11 @@ class UsersControllerTest extends TestCase {
'setPassword' => false,
],
'additional_mail' => [],
'organisation' => 'organisation',
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1',
'notify_email' => null,
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
@@ -1543,6 +1577,11 @@ class UsersControllerTest extends TestCase {
[IAccountManager::PROPERTY_PHONE, '1234', '12345'],
[IAccountManager::PROPERTY_ADDRESS, 'Something street 2', 'Another street 3'],
[IAccountManager::PROPERTY_WEBSITE, 'https://examplesite1', 'https://examplesite2'],
[IAccountManager::PROPERTY_ORGANISATION, 'Organisation A', 'Organisation B'],
[IAccountManager::PROPERTY_ROLE, 'Human', 'Alien'],
[IAccountManager::PROPERTY_HEADLINE, 'Hi', 'Hello'],
[IAccountManager::PROPERTY_BIOGRAPHY, 'A biography', 'Another biography'],
[IAccountManager::PROPERTY_PROFILE_ENABLED, '1', '0'],
];
}

@@ -1614,6 +1653,11 @@ class UsersControllerTest extends TestCase {
[IAccountManager::PROPERTY_PHONE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_ADDRESS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_WEBSITE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_ORGANISATION, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_ROLE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_HEADLINE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_BIOGRAPHY, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_PROFILE_ENABLED, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
];
}

@@ -3490,7 +3534,12 @@ class UsersControllerTest extends TestCase {
'phone' => 'phone',
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter'
'twitter' => 'twitter',
'organisation' => 'organisation',
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1'
]
);

@@ -3503,6 +3552,11 @@ class UsersControllerTest extends TestCase {
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
'organisation' => 'organisation',
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1',
'display-name' => 'Demo User'
];

@@ -3560,7 +3614,12 @@ class UsersControllerTest extends TestCase {
'address' => 'address',
'website' => 'website',
'twitter' => 'twitter',
'displayname' => 'Demo User'
'displayname' => 'Demo User',
'organisation' => 'organisation',
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1'
];

$api->expects($this->at(0))->method('getUserData')
@@ -3878,6 +3937,11 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[true, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_DISPLAYNAME,
@@ -3887,6 +3951,11 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
[true, UserInterface::class, [
IAccountManager::PROPERTY_EMAIL,
@@ -3895,6 +3964,11 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
]],
];
}
@@ -3941,7 +4015,7 @@ class UsersControllerTest extends TestCase {

$account = $this->createMock(IAccount::class);
$account->method('getProperty')
->will($this->returnValueMap($mockedProperties));
->will($this->returnValueMap($mockedProperties));

$this->accountManager->expects($this->any())->method('getAccount')
->with($targetUser)

+ 15
- 0
build/integration/features/provisioning-v1.feature View File

@@ -67,6 +67,11 @@ Feature: provisioning
| address |
| website |
| twitter |
| organisation |
| role |
| headline |
| biography |
| profile_enabled |
Given As an "brand-new-user"
Then user "brand-new-user" has editable fields
| displayname |
@@ -76,6 +81,11 @@ Feature: provisioning
| address |
| website |
| twitter |
| organisation |
| role |
| headline |
| biography |
| profile_enabled |
Then user "self" has editable fields
| displayname |
| email |
@@ -84,6 +94,11 @@ Feature: provisioning
| address |
| website |
| twitter |
| organisation |
| role |
| headline |
| biography |
| profile_enabled |

Scenario: Edit a user
Given As an "admin"

+ 48
- 12
lib/private/Accounts/AccountManager.php View File

@@ -1,4 +1,5 @@
<?php

/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @copyright Copyright (c) 2016, Björn Schießle
@@ -30,6 +31,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\Accounts;

use Exception;
@@ -337,7 +339,7 @@ class AccountManager implements IAccountManager {
return $this->buildDefaultUserRecord($user);
}

return $this->addMissingDefaultValues($userDataArray);
return $this->addMissingDefaultValues($userDataArray, $this->buildDefaultUserRecord($user));
}

public function searchUsers(string $property, array $values): array {
@@ -384,7 +386,8 @@ class AccountManager implements IAccountManager {
}
$oldMail = isset($oldData[self::PROPERTY_EMAIL]) ? $oldData[self::PROPERTY_EMAIL]['value']['value'] : '';
if ($oldMail !== $property->getValue()) {
$this->jobList->add(VerifyUserData::class,
$this->jobList->add(
VerifyUserData::class,
[
'verificationCode' => '',
'data' => $property->getValue(),
@@ -416,12 +419,14 @@ class AccountManager implements IAccountManager {
$key = $this->crypto->encrypt($email);
$token = $this->verificationToken->create($user, 'verifyMail' . $ref, $email);

$link = $this->urlGenerator->linkToRouteAbsolute('provisioning_api.Verification.verifyMail',
$link = $this->urlGenerator->linkToRouteAbsolute(
'provisioning_api.Verification.verifyMail',
[
'userId' => $user->getUID(),
'token' => $token,
'key' => $key
]);
]
);

$emailTemplate = $this->mailer->createEMailTemplate('core.EmailVerification', [
'link' => $link,
@@ -465,14 +470,18 @@ class AccountManager implements IAccountManager {
}

/**
* make sure that all expected data are set
*
* Make sure that all expected data are set
*/
protected function addMissingDefaultValues(array $userData): array {
foreach ($userData as $i => $value) {
if (!isset($value['verified'])) {
$userData[$i]['verified'] = self::NOT_VERIFIED;
protected function addMissingDefaultValues(array $userData, array $defaultUserData): array {
foreach ($defaultUserData as $i => $value) {
// If property doesn't exists, initialize it
if (!array_key_exists($i, $userData)) {
$userData[$i] = [];
}

// Merge and extend default missing values
$defaultValueIndex = array_search($value['name'], array_column($defaultUserData, 'name'));
$userData[$i] = array_merge($defaultUserData[$defaultValueIndex], $userData[$i]);
}

return $userData;
@@ -499,7 +508,7 @@ class AccountManager implements IAccountManager {
|| $property->getValue() !== $oldData[$propertyName]['value'])
&& ($property->getVerified() !== self::NOT_VERIFIED
|| $wasVerified)
) {
) {
$property->setVerified(self::NOT_VERIFIED);
}
}
@@ -629,7 +638,6 @@ class AccountManager implements IAccountManager {
*/
protected function buildDefaultUserRecord(IUser $user) {
return [

[
'name' => self::PROPERTY_DISPLAYNAME,
'value' => $user->getDisplayName(),
@@ -677,6 +685,34 @@ class AccountManager implements IAccountManager {
'verified' => self::NOT_VERIFIED,
],

[
'name' => self::PROPERTY_ORGANISATION,
'value' => '',
'scope' => self::SCOPE_LOCAL,
],

[
'name' => self::PROPERTY_ROLE,
'value' => '',
'scope' => self::SCOPE_LOCAL,
],

[
'name' => self::PROPERTY_HEADLINE,
'value' => '',
'scope' => self::SCOPE_LOCAL,
],

[
'name' => self::PROPERTY_BIOGRAPHY,
'value' => '',
'scope' => self::SCOPE_LOCAL,
],

[
'name' => self::PROPERTY_PROFILE_ENABLED,
'value' => '1',
],
];
}


+ 5
- 1
lib/private/Accounts/TAccountsHelper.php View File

@@ -29,8 +29,12 @@ namespace OC\Accounts;
use OCP\Accounts\IAccountManager;

trait TAccountsHelper {
/**
* returns whether the property is a collection
*/
protected function isCollection(string $propertyName): bool {
return in_array($propertyName,
return in_array(
$propertyName,
[
IAccountManager::COLLECTION_EMAIL,
],

+ 24
- 20
lib/private/L10N/Factory.php View File

@@ -37,6 +37,7 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\L10N;

use OCP\IConfig;
@@ -104,10 +105,12 @@ class Factory implements IFactory {
* @param IUserSession $userSession
* @param string $serverRoot
*/
public function __construct(IConfig $config,
IRequest $request,
IUserSession $userSession,
$serverRoot) {
public function __construct(
IConfig $config,
IRequest $request,
IUserSession $userSession,
$serverRoot
) {
$this->config = $config;
$this->request = $request;
$this->userSession = $userSession;
@@ -149,7 +152,10 @@ class Factory implements IFactory {

if (!isset($this->instances[$lang][$app])) {
$this->instances[$lang][$app] = new L10N(
$this, $app, $lang, $locale,
$this,
$app,
$lang,
$locale,
$this->getL10nFilesForApp($app, $lang)
);
}
@@ -391,7 +397,7 @@ class Factory implements IFactory {
* @return bool
*/
public function languageExists($app, $lang) {
if ($lang === 'en') {//english is always available
if ($lang === 'en') { //english is always available
return true;
}

@@ -493,7 +499,8 @@ class Factory implements IFactory {

// use formal version of german ("Sie" instead of "Du") if the default
// language is set to 'de_DE' if possible
if (is_string($defaultLanguage) &&
if (
is_string($defaultLanguage) &&
strtolower($lang) === 'de' &&
strtolower($defaultLanguage) === 'de_de' &&
$this->languageExists($app, 'de_DE')
@@ -542,9 +549,9 @@ class Factory implements IFactory {

if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
|| $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
)
&& file_exists($transFile)) {
|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/'))
&& file_exists($transFile)
) {
// load the translations file
$languageFiles[] = $transFile;
}
@@ -599,9 +606,9 @@ class Factory implements IFactory {
$plural = preg_replace('#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2]);

$body = str_replace(
[ 'plural', 'n', '$n$plurals', ],
[ '$plural', '$n', '$nplurals', ],
'nplurals='. $nplurals . '; plural=' . $plural
['plural', 'n', '$n$plurals',],
['$plural', '$n', '$nplurals',],
'nplurals=' . $nplurals . '; plural=' . $plural
);

// add parents
@@ -645,12 +652,9 @@ class Factory implements IFactory {
}

/**
* returns the common language and other languages in an
* associative array
*
* @return array
* @inheritDoc
*/
public function getLanguages() {
public function getLanguages(): array {
$forceLanguage = $this->config->getSystemValue('force_language', false);
if ($forceLanguage !== false) {
$l = $this->get('lib', $forceLanguage);
@@ -674,7 +678,7 @@ class Factory implements IFactory {
$l = $this->get('lib', $lang);
// TRANSLATORS this is the language name for the language switcher in the personal settings and should be the localized version
$potentialName = $l->t('__language_name__');
if ($l->getLanguageCode() === $lang && $potentialName[0] !== '_') {//first check if the language name is in the translation file
if ($l->getLanguageCode() === $lang && $potentialName[0] !== '_') { //first check if the language name is in the translation file
$ln = [
'code' => $lang,
'name' => $potentialName
@@ -684,7 +688,7 @@ class Factory implements IFactory {
'code' => $lang,
'name' => 'English (US)'
];
} else {//fallback to language code
} else { //fallback to language code
$ln = [
'code' => $lang,
'name' => $lang

+ 9
- 0
lib/public/L10N/IFactory.php View File

@@ -29,6 +29,7 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCP\L10N;

use OCP\IUser;
@@ -151,6 +152,14 @@ interface IFactory {
*/
public function getLanguageIterator(IUser $user = null): ILanguageIterator;

/**
* returns the common language and other languages in an
* associative array
*
* @since 23.0.0
*/
public function getLanguages(): array;

/**
* Return the language to use when sending something to a user
*

+ 192
- 6
tests/lib/Accounts/AccountManagerTest.php View File

@@ -1,4 +1,5 @@
<?php

/**
* @author Björn Schießle <schiessle@owncloud.com>
*
@@ -168,6 +169,26 @@ class AccountManagerTest extends TestCase {
'value' => 'https://acme.com',
'scope' => IAccountManager::SCOPE_PRIVATE
],
[
'name' => IAccountManager::PROPERTY_ORGANISATION,
'value' => 'Some organisation',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_ROLE,
'value' => 'Human',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_HEADLINE,
'value' => 'Hi',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_BIOGRAPHY,
'value' => 'Biography',
'scope' => IAccountManager::SCOPE_LOCAL
],
],
],
[
@@ -203,6 +224,26 @@ class AccountManagerTest extends TestCase {
'value' => 'https://example.org',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_ORGANISATION,
'value' => 'Another organisation',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_ROLE,
'value' => 'Alien',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_HEADLINE,
'value' => 'Hello',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_BIOGRAPHY,
'value' => 'Different biography',
'scope' => IAccountManager::SCOPE_FEDERATED
],
],
],
[
@@ -238,6 +279,26 @@ class AccountManagerTest extends TestCase {
'value' => 'https://example.com',
'scope' => IAccountManager::SCOPE_PUBLISHED
],
[
'name' => IAccountManager::PROPERTY_ORGANISATION,
'value' => 'Yet another organisation',
'scope' => IAccountManager::SCOPE_PUBLISHED
],
[
'name' => IAccountManager::PROPERTY_ROLE,
'value' => 'Being',
'scope' => IAccountManager::SCOPE_PUBLISHED
],
[
'name' => IAccountManager::PROPERTY_HEADLINE,
'value' => 'This is a headline',
'scope' => IAccountManager::SCOPE_PUBLISHED
],
[
'name' => IAccountManager::PROPERTY_BIOGRAPHY,
'value' => 'Some long biography',
'scope' => IAccountManager::SCOPE_PUBLISHED
],
],
],
[
@@ -273,6 +334,26 @@ class AccountManagerTest extends TestCase {
'value' => 'https://emca.com',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_ORGANISATION,
'value' => 'Organisation A',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_ROLE,
'value' => 'Animal',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_HEADLINE,
'value' => 'My headline',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::PROPERTY_BIOGRAPHY,
'value' => 'Short biography',
'scope' => IAccountManager::SCOPE_LOCAL
],
[
'name' => IAccountManager::COLLECTION_EMAIL,
'value' => 'k.cheng@emca.com',
@@ -318,6 +399,26 @@ class AccountManagerTest extends TestCase {
'value' => 'https://elpmaxe.org',
'scope' => IAccountManager::SCOPE_PUBLISHED
],
[
'name' => IAccountManager::PROPERTY_ORGANISATION,
'value' => 'Organisation B',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_ROLE,
'value' => 'Organism',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_HEADLINE,
'value' => 'Best headline',
'scope' => IAccountManager::SCOPE_FEDERATED
],
[
'name' => IAccountManager::PROPERTY_BIOGRAPHY,
'value' => 'Autobiography',
'scope' => IAccountManager::SCOPE_FEDERATED
],
],
],
];
@@ -406,18 +507,103 @@ class AccountManagerTest extends TestCase {
];
}

public function testAddMissingDefaultValues() {
public function testAddMissingDefaults() {
$user = $this->createMock(IUser::class);

$input = [
['value' => 'value1', 'verified' => '0', 'name' => 'key1'],
['value' => 'value1', 'name' => 'key2'],
[
'name' => IAccountManager::PROPERTY_DISPLAYNAME,
'value' => 'bob',
'verified' => IAccountManager::NOT_VERIFIED,
],
[],
[],
[
'name' => IAccountManager::PROPERTY_EMAIL,
'value' => 'bob@bob.bob',
],
];

$expected = [
['value' => 'value1', 'verified' => '0', 'name' => 'key1'],
['value' => 'value1', 'name' => 'key2', 'verified' => '0'],
[
'name' => IAccountManager::PROPERTY_DISPLAYNAME,
'value' => 'bob',
'scope' => IAccountManager::SCOPE_FEDERATED,
'verified' => IAccountManager::NOT_VERIFIED,
],

[
'name' => IAccountManager::PROPERTY_ADDRESS,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
'verified' => IAccountManager::NOT_VERIFIED,
],

[
'name' => IAccountManager::PROPERTY_WEBSITE,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
'verified' => IAccountManager::NOT_VERIFIED,
],

[
'name' => IAccountManager::PROPERTY_EMAIL,
'value' => 'bob@bob.bob',
'scope' => IAccountManager::SCOPE_FEDERATED,
'verified' => IAccountManager::NOT_VERIFIED,
],

[
'name' => IAccountManager::PROPERTY_AVATAR,
'scope' => IAccountManager::SCOPE_FEDERATED
],

[
'name' => IAccountManager::PROPERTY_PHONE,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
'verified' => IAccountManager::NOT_VERIFIED,
],

[
'name' => IAccountManager::PROPERTY_TWITTER,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
'verified' => IAccountManager::NOT_VERIFIED,
],

[
'name' => IAccountManager::PROPERTY_ORGANISATION,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
],

[
'name' => IAccountManager::PROPERTY_ROLE,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
],

[
'name' => IAccountManager::PROPERTY_HEADLINE,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
],

[
'name' => IAccountManager::PROPERTY_BIOGRAPHY,
'value' => '',
'scope' => IAccountManager::SCOPE_LOCAL,
],

[
'name' => IAccountManager::PROPERTY_PROFILE_ENABLED,
'value' => '1',
],
];

$result = $this->invokePrivate($this->accountManager, 'addMissingDefaultValues', [$input]);
$defaultUserRecord = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
$result = $this->invokePrivate($this->accountManager, 'addMissingDefaultValues', [$input, $defaultUserRecord]);

$this->assertSame($expected, $result);
}

Loading…
Cancel
Save