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>
pull/28751/head
Christopher Ng 4 years ago
parent 382ba66ab5
commit 7215148a24
  1. 5
      apps/provisioning_api/lib/Controller/AUserData.php
  2. 191
      apps/provisioning_api/lib/Controller/UsersController.php
  3. 94
      apps/provisioning_api/tests/Controller/UsersControllerTest.php
  4. 15
      build/integration/features/provisioning-v1.feature
  5. 60
      lib/private/Accounts/AccountManager.php
  6. 6
      lib/private/Accounts/TAccountsHelper.php
  7. 44
      lib/private/L10N/Factory.php
  8. 9
      lib/public/L10N/IFactory.php
  9. 198
      tests/lib/Accounts/AccountManagerTest.php

@ -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();

@ -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,

@ -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)

@ -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"

@ -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',
],
];
}

@ -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,
],

@ -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

@ -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
*

@ -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