You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AccountManagerTest.php 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Björn Schießle <schiessle@owncloud.com>
  6. * @author Thomas Citharel <nextcloud@tcit.fr>
  7. *
  8. * @license AGPL-3.0
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace Test\Accounts;
  24. use OC\Accounts\Account;
  25. use OC\Accounts\AccountManager;
  26. use OCA\Settings\BackgroundJobs\VerifyUserData;
  27. use OCP\Accounts\IAccountManager;
  28. use OCP\BackgroundJob\IJobList;
  29. use OCP\Defaults;
  30. use OCP\IConfig;
  31. use OCP\IDBConnection;
  32. use OCP\IURLGenerator;
  33. use OCP\IUser;
  34. use OCP\L10N\IFactory;
  35. use OCP\Mail\IMailer;
  36. use OCP\Security\ICrypto;
  37. use OCP\Security\VerificationToken\IVerificationToken;
  38. use PHPUnit\Framework\MockObject\MockObject;
  39. use Psr\Log\LoggerInterface;
  40. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  41. use Symfony\Component\EventDispatcher\GenericEvent;
  42. use Test\TestCase;
  43. /**
  44. * Class AccountManagerTest
  45. *
  46. * @group DB
  47. * @package Test\Accounts
  48. */
  49. class AccountManagerTest extends TestCase {
  50. /** @var IVerificationToken|MockObject */
  51. protected $verificationToken;
  52. /** @var IMailer|MockObject */
  53. protected $mailer;
  54. /** @var ICrypto|MockObject */
  55. protected $crypto;
  56. /** @var IURLGenerator|MockObject */
  57. protected $urlGenerator;
  58. /** @var Defaults|MockObject */
  59. protected $defaults;
  60. /** @var IFactory|MockObject */
  61. protected $l10nFactory;
  62. /** @var IDBConnection */
  63. private $connection;
  64. /** @var IConfig|MockObject */
  65. private $config;
  66. /** @var EventDispatcherInterface|MockObject */
  67. private $eventDispatcher;
  68. /** @var IJobList|MockObject */
  69. private $jobList;
  70. /** accounts table name */
  71. private string $table = 'accounts';
  72. /** @var LoggerInterface|MockObject */
  73. private $logger;
  74. private AccountManager $accountManager;
  75. protected function setUp(): void {
  76. parent::setUp();
  77. $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
  78. $this->connection = \OC::$server->get(IDBConnection::class);
  79. $this->config = $this->createMock(IConfig::class);
  80. $this->jobList = $this->createMock(IJobList::class);
  81. $this->logger = $this->createMock(LoggerInterface::class);
  82. $this->verificationToken = $this->createMock(IVerificationToken::class);
  83. $this->mailer = $this->createMock(IMailer::class);
  84. $this->defaults = $this->createMock(Defaults::class);
  85. $this->l10nFactory = $this->createMock(IFactory::class);
  86. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  87. $this->crypto = $this->createMock(ICrypto::class);
  88. $this->accountManager = new AccountManager(
  89. $this->connection,
  90. $this->config,
  91. $this->eventDispatcher,
  92. $this->jobList,
  93. $this->logger,
  94. $this->verificationToken,
  95. $this->mailer,
  96. $this->defaults,
  97. $this->l10nFactory,
  98. $this->urlGenerator,
  99. $this->crypto
  100. );
  101. }
  102. protected function tearDown(): void {
  103. parent::tearDown();
  104. $query = $this->connection->getQueryBuilder();
  105. $query->delete($this->table)->executeStatement();
  106. }
  107. protected function makeUser(string $uid, string $name, string $email = null): IUser {
  108. $user = $this->createMock(IUser::class);
  109. $user->expects($this->any())
  110. ->method('getUid')
  111. ->willReturn($uid);
  112. $user->expects($this->any())
  113. ->method('getDisplayName')
  114. ->willReturn($name);
  115. if ($email !== null) {
  116. $user->expects($this->any())
  117. ->method('getEMailAddress')
  118. ->willReturn($email);
  119. }
  120. return $user;
  121. }
  122. protected function populateOrUpdate(): void {
  123. $users = [
  124. [
  125. 'user' => $this->makeUser('j.doe', 'Jane Doe', 'jane.doe@acme.com'),
  126. 'data' => [
  127. [
  128. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  129. 'value' => 'Jane Doe',
  130. 'scope' => IAccountManager::SCOPE_PUBLISHED
  131. ],
  132. [
  133. 'name' => IAccountManager::PROPERTY_EMAIL,
  134. 'value' => 'jane.doe@acme.com',
  135. 'scope' => IAccountManager::SCOPE_LOCAL
  136. ],
  137. [
  138. 'name' => IAccountManager::PROPERTY_TWITTER,
  139. 'value' => '@sometwitter',
  140. 'scope' => IAccountManager::SCOPE_PUBLISHED
  141. ],
  142. [
  143. 'name' => IAccountManager::PROPERTY_PHONE,
  144. 'value' => '+491601231212',
  145. 'scope' => IAccountManager::SCOPE_FEDERATED
  146. ],
  147. [
  148. 'name' => IAccountManager::PROPERTY_ADDRESS,
  149. 'value' => 'some street',
  150. 'scope' => IAccountManager::SCOPE_LOCAL
  151. ],
  152. [
  153. 'name' => IAccountManager::PROPERTY_WEBSITE,
  154. 'value' => 'https://acme.com',
  155. 'scope' => IAccountManager::SCOPE_PRIVATE
  156. ],
  157. [
  158. 'name' => IAccountManager::PROPERTY_ORGANISATION,
  159. 'value' => 'Some organisation',
  160. 'scope' => IAccountManager::SCOPE_LOCAL
  161. ],
  162. [
  163. 'name' => IAccountManager::PROPERTY_ROLE,
  164. 'value' => 'Human',
  165. 'scope' => IAccountManager::SCOPE_LOCAL
  166. ],
  167. [
  168. 'name' => IAccountManager::PROPERTY_HEADLINE,
  169. 'value' => 'Hi',
  170. 'scope' => IAccountManager::SCOPE_LOCAL
  171. ],
  172. [
  173. 'name' => IAccountManager::PROPERTY_BIOGRAPHY,
  174. 'value' => 'Biography',
  175. 'scope' => IAccountManager::SCOPE_LOCAL
  176. ],
  177. ],
  178. ],
  179. [
  180. 'user' => $this->makeUser('a.allison', 'Alice Allison', 'a.allison@example.org'),
  181. 'data' => [
  182. [
  183. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  184. 'value' => 'Alice Allison',
  185. 'scope' => IAccountManager::SCOPE_LOCAL
  186. ],
  187. [
  188. 'name' => IAccountManager::PROPERTY_EMAIL,
  189. 'value' => 'a.allison@example.org',
  190. 'scope' => IAccountManager::SCOPE_LOCAL
  191. ],
  192. [
  193. 'name' => IAccountManager::PROPERTY_TWITTER,
  194. 'value' => '@a_alice',
  195. 'scope' => IAccountManager::SCOPE_FEDERATED
  196. ],
  197. [
  198. 'name' => IAccountManager::PROPERTY_PHONE,
  199. 'value' => '+491602312121',
  200. 'scope' => IAccountManager::SCOPE_LOCAL
  201. ],
  202. [
  203. 'name' => IAccountManager::PROPERTY_ADDRESS,
  204. 'value' => 'Dundee Road 45',
  205. 'scope' => IAccountManager::SCOPE_LOCAL
  206. ],
  207. [
  208. 'name' => IAccountManager::PROPERTY_WEBSITE,
  209. 'value' => 'https://example.org',
  210. 'scope' => IAccountManager::SCOPE_LOCAL
  211. ],
  212. [
  213. 'name' => IAccountManager::PROPERTY_ORGANISATION,
  214. 'value' => 'Another organisation',
  215. 'scope' => IAccountManager::SCOPE_FEDERATED
  216. ],
  217. [
  218. 'name' => IAccountManager::PROPERTY_ROLE,
  219. 'value' => 'Alien',
  220. 'scope' => IAccountManager::SCOPE_FEDERATED
  221. ],
  222. [
  223. 'name' => IAccountManager::PROPERTY_HEADLINE,
  224. 'value' => 'Hello',
  225. 'scope' => IAccountManager::SCOPE_FEDERATED
  226. ],
  227. [
  228. 'name' => IAccountManager::PROPERTY_BIOGRAPHY,
  229. 'value' => 'Different biography',
  230. 'scope' => IAccountManager::SCOPE_FEDERATED
  231. ],
  232. ],
  233. ],
  234. [
  235. 'user' => $this->makeUser('b32c5a5b-1084-4380-8856-e5223b16de9f', 'Armel Oliseh', 'oliseh@example.com'),
  236. 'data' => [
  237. [
  238. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  239. 'value' => 'Armel Oliseh',
  240. 'scope' => IAccountManager::SCOPE_PUBLISHED
  241. ],
  242. [
  243. 'name' => IAccountManager::PROPERTY_EMAIL,
  244. 'value' => 'oliseh@example.com',
  245. 'scope' => IAccountManager::SCOPE_PUBLISHED
  246. ],
  247. [
  248. 'name' => IAccountManager::PROPERTY_TWITTER,
  249. 'value' => '',
  250. 'scope' => IAccountManager::SCOPE_LOCAL
  251. ],
  252. [
  253. 'name' => IAccountManager::PROPERTY_PHONE,
  254. 'value' => '+491603121212',
  255. 'scope' => IAccountManager::SCOPE_PUBLISHED
  256. ],
  257. [
  258. 'name' => IAccountManager::PROPERTY_ADDRESS,
  259. 'value' => 'Sunflower Blvd. 77',
  260. 'scope' => IAccountManager::SCOPE_PUBLISHED
  261. ],
  262. [
  263. 'name' => IAccountManager::PROPERTY_WEBSITE,
  264. 'value' => 'https://example.com',
  265. 'scope' => IAccountManager::SCOPE_PUBLISHED
  266. ],
  267. [
  268. 'name' => IAccountManager::PROPERTY_ORGANISATION,
  269. 'value' => 'Yet another organisation',
  270. 'scope' => IAccountManager::SCOPE_PUBLISHED
  271. ],
  272. [
  273. 'name' => IAccountManager::PROPERTY_ROLE,
  274. 'value' => 'Being',
  275. 'scope' => IAccountManager::SCOPE_PUBLISHED
  276. ],
  277. [
  278. 'name' => IAccountManager::PROPERTY_HEADLINE,
  279. 'value' => 'This is a headline',
  280. 'scope' => IAccountManager::SCOPE_PUBLISHED
  281. ],
  282. [
  283. 'name' => IAccountManager::PROPERTY_BIOGRAPHY,
  284. 'value' => 'Some long biography',
  285. 'scope' => IAccountManager::SCOPE_PUBLISHED
  286. ],
  287. ],
  288. ],
  289. [
  290. 'user' => $this->makeUser('31b5316a-9b57-4b17-970a-315a4cbe73eb', 'K. Cheng', 'cheng@emca.com'),
  291. 'data' => [
  292. [
  293. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  294. 'value' => 'K. Cheng',
  295. 'scope' => IAccountManager::SCOPE_FEDERATED
  296. ],
  297. [
  298. 'name' => IAccountManager::PROPERTY_EMAIL,
  299. 'value' => 'cheng@emca.com',
  300. 'scope' => IAccountManager::SCOPE_FEDERATED
  301. ],
  302. [
  303. 'name' => IAccountManager::PROPERTY_TWITTER,
  304. 'value' => '', '
  305. scope' => IAccountManager::SCOPE_LOCAL
  306. ],
  307. [
  308. 'name' => IAccountManager::PROPERTY_PHONE,
  309. 'value' => '+71601212123',
  310. 'scope' => IAccountManager::SCOPE_LOCAL
  311. ],
  312. [
  313. 'name' => IAccountManager::PROPERTY_ADDRESS,
  314. 'value' => 'Pinapple Street 22',
  315. 'scope' => IAccountManager::SCOPE_LOCAL
  316. ],
  317. [
  318. 'name' => IAccountManager::PROPERTY_WEBSITE,
  319. 'value' => 'https://emca.com',
  320. 'scope' => IAccountManager::SCOPE_FEDERATED
  321. ],
  322. [
  323. 'name' => IAccountManager::PROPERTY_ORGANISATION,
  324. 'value' => 'Organisation A',
  325. 'scope' => IAccountManager::SCOPE_LOCAL
  326. ],
  327. [
  328. 'name' => IAccountManager::PROPERTY_ROLE,
  329. 'value' => 'Animal',
  330. 'scope' => IAccountManager::SCOPE_LOCAL
  331. ],
  332. [
  333. 'name' => IAccountManager::PROPERTY_HEADLINE,
  334. 'value' => 'My headline',
  335. 'scope' => IAccountManager::SCOPE_LOCAL
  336. ],
  337. [
  338. 'name' => IAccountManager::PROPERTY_BIOGRAPHY,
  339. 'value' => 'Short biography',
  340. 'scope' => IAccountManager::SCOPE_LOCAL
  341. ],
  342. [
  343. 'name' => IAccountManager::COLLECTION_EMAIL,
  344. 'value' => 'k.cheng@emca.com',
  345. 'scope' => IAccountManager::SCOPE_LOCAL
  346. ],
  347. [
  348. 'name' => IAccountManager::COLLECTION_EMAIL,
  349. 'value' => 'kai.cheng@emca.com',
  350. 'scope' => IAccountManager::SCOPE_LOCAL
  351. ],
  352. ],
  353. ],
  354. [
  355. 'user' => $this->makeUser('goodpal@elpmaxe.org', 'Goodpal, Kim', 'goodpal@elpmaxe.org'),
  356. 'data' => [
  357. [
  358. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  359. 'value' => 'Goodpal, Kim',
  360. 'scope' => IAccountManager::SCOPE_PUBLISHED
  361. ],
  362. [
  363. 'name' => IAccountManager::PROPERTY_EMAIL,
  364. 'value' => 'goodpal@elpmaxe.org',
  365. 'scope' => IAccountManager::SCOPE_PUBLISHED
  366. ],
  367. [
  368. 'name' => IAccountManager::PROPERTY_TWITTER,
  369. 'value' => '',
  370. 'scope' => IAccountManager::SCOPE_LOCAL
  371. ],
  372. [
  373. 'name' => IAccountManager::PROPERTY_PHONE,
  374. 'value' => '+71602121231',
  375. 'scope' => IAccountManager::SCOPE_FEDERATED
  376. ],
  377. [
  378. 'name' => IAccountManager::PROPERTY_ADDRESS,
  379. 'value' => 'Octopus Ave 17',
  380. 'scope' => IAccountManager::SCOPE_FEDERATED
  381. ],
  382. [
  383. 'name' => IAccountManager::PROPERTY_WEBSITE,
  384. 'value' => 'https://elpmaxe.org',
  385. 'scope' => IAccountManager::SCOPE_PUBLISHED
  386. ],
  387. [
  388. 'name' => IAccountManager::PROPERTY_ORGANISATION,
  389. 'value' => 'Organisation B',
  390. 'scope' => IAccountManager::SCOPE_FEDERATED
  391. ],
  392. [
  393. 'name' => IAccountManager::PROPERTY_ROLE,
  394. 'value' => 'Organism',
  395. 'scope' => IAccountManager::SCOPE_FEDERATED
  396. ],
  397. [
  398. 'name' => IAccountManager::PROPERTY_HEADLINE,
  399. 'value' => 'Best headline',
  400. 'scope' => IAccountManager::SCOPE_FEDERATED
  401. ],
  402. [
  403. 'name' => IAccountManager::PROPERTY_BIOGRAPHY,
  404. 'value' => 'Autobiography',
  405. 'scope' => IAccountManager::SCOPE_FEDERATED
  406. ],
  407. ],
  408. ],
  409. ];
  410. $this->config->expects($this->exactly(count($users)))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
  411. foreach ($users as $userInfo) {
  412. $this->invokePrivate($this->accountManager, 'updateUser', [$userInfo['user'], $userInfo['data'], null, false]);
  413. }
  414. }
  415. /**
  416. * get a instance of the accountManager
  417. *
  418. * @return MockObject | AccountManager
  419. */
  420. public function getInstance(?array $mockedMethods = null) {
  421. return $this->getMockBuilder(AccountManager::class)
  422. ->setConstructorArgs([
  423. $this->connection,
  424. $this->config,
  425. $this->eventDispatcher,
  426. $this->jobList,
  427. $this->logger,
  428. $this->verificationToken,
  429. $this->mailer,
  430. $this->defaults,
  431. $this->l10nFactory,
  432. $this->urlGenerator,
  433. $this->crypto
  434. ])
  435. ->onlyMethods($mockedMethods)
  436. ->getMock();
  437. }
  438. /**
  439. * @dataProvider dataTrueFalse
  440. *
  441. */
  442. public function testUpdateUser(array $newData, array $oldData, bool $insertNew, bool $updateExisting) {
  443. $accountManager = $this->getInstance(['getUser', 'insertNewUser', 'updateExistingUser']);
  444. /** @var IUser $user */
  445. $user = $this->createMock(IUser::class);
  446. if ($updateExisting) {
  447. $accountManager->expects($this->once())->method('updateExistingUser')
  448. ->with($user, $newData);
  449. $accountManager->expects($this->never())->method('insertNewUser');
  450. }
  451. if ($insertNew) {
  452. $accountManager->expects($this->once())->method('insertNewUser')
  453. ->with($user, $newData);
  454. $accountManager->expects($this->never())->method('updateExistingUser');
  455. }
  456. if (!$insertNew && !$updateExisting) {
  457. $accountManager->expects($this->never())->method('updateExistingUser');
  458. $accountManager->expects($this->never())->method('insertNewUser');
  459. $this->eventDispatcher->expects($this->never())->method('dispatch');
  460. } else {
  461. $this->eventDispatcher->expects($this->once())->method('dispatch')
  462. ->willReturnCallback(
  463. function ($eventName, $event) use ($user, $newData) {
  464. $this->assertSame('OC\AccountManager::userUpdated', $eventName);
  465. $this->assertInstanceOf(GenericEvent::class, $event);
  466. $this->assertSame($user, $event->getSubject());
  467. $this->assertSame($newData, $event->getArguments());
  468. }
  469. );
  470. }
  471. $this->invokePrivate($accountManager, 'updateUser', [$user, $newData, $oldData]);
  472. }
  473. public function dataTrueFalse(): array {
  474. return [
  475. #$newData | $oldData | $insertNew | $updateExisting
  476. [['myProperty' => ['value' => 'newData']], ['myProperty' => ['value' => 'oldData']], false, true],
  477. [['myProperty' => ['value' => 'oldData']], ['myProperty' => ['value' => 'oldData']], false, false]
  478. ];
  479. }
  480. public function testAddMissingDefaults() {
  481. $user = $this->createMock(IUser::class);
  482. $this->config
  483. ->expects($this->once())
  484. ->method('getAppValue')
  485. ->with('settings', 'profile_enabled_by_default', '1')
  486. ->willReturn('1');
  487. $input = [
  488. [
  489. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  490. 'value' => 'bob',
  491. 'verified' => IAccountManager::NOT_VERIFIED,
  492. ],
  493. [
  494. 'name' => IAccountManager::PROPERTY_EMAIL,
  495. 'value' => 'bob@bob.bob',
  496. ],
  497. ];
  498. $expected = [
  499. [
  500. 'name' => IAccountManager::PROPERTY_DISPLAYNAME,
  501. 'value' => 'bob',
  502. 'scope' => IAccountManager::SCOPE_FEDERATED,
  503. 'verified' => IAccountManager::NOT_VERIFIED,
  504. ],
  505. [
  506. 'name' => IAccountManager::PROPERTY_EMAIL,
  507. 'value' => 'bob@bob.bob',
  508. 'scope' => IAccountManager::SCOPE_FEDERATED,
  509. 'verified' => IAccountManager::NOT_VERIFIED,
  510. ],
  511. [
  512. 'name' => IAccountManager::PROPERTY_ADDRESS,
  513. 'value' => '',
  514. 'scope' => IAccountManager::SCOPE_LOCAL,
  515. 'verified' => IAccountManager::NOT_VERIFIED,
  516. ],
  517. [
  518. 'name' => IAccountManager::PROPERTY_WEBSITE,
  519. 'value' => '',
  520. 'scope' => IAccountManager::SCOPE_LOCAL,
  521. 'verified' => IAccountManager::NOT_VERIFIED,
  522. ],
  523. [
  524. 'name' => IAccountManager::PROPERTY_AVATAR,
  525. 'scope' => IAccountManager::SCOPE_FEDERATED
  526. ],
  527. [
  528. 'name' => IAccountManager::PROPERTY_PHONE,
  529. 'value' => '',
  530. 'scope' => IAccountManager::SCOPE_LOCAL,
  531. 'verified' => IAccountManager::NOT_VERIFIED,
  532. ],
  533. [
  534. 'name' => IAccountManager::PROPERTY_TWITTER,
  535. 'value' => '',
  536. 'scope' => IAccountManager::SCOPE_LOCAL,
  537. 'verified' => IAccountManager::NOT_VERIFIED,
  538. ],
  539. [
  540. 'name' => IAccountManager::PROPERTY_ORGANISATION,
  541. 'value' => '',
  542. 'scope' => IAccountManager::SCOPE_LOCAL,
  543. ],
  544. [
  545. 'name' => IAccountManager::PROPERTY_ROLE,
  546. 'value' => '',
  547. 'scope' => IAccountManager::SCOPE_LOCAL,
  548. ],
  549. [
  550. 'name' => IAccountManager::PROPERTY_HEADLINE,
  551. 'value' => '',
  552. 'scope' => IAccountManager::SCOPE_LOCAL,
  553. ],
  554. [
  555. 'name' => IAccountManager::PROPERTY_BIOGRAPHY,
  556. 'value' => '',
  557. 'scope' => IAccountManager::SCOPE_LOCAL,
  558. ],
  559. [
  560. 'name' => IAccountManager::PROPERTY_PROFILE_ENABLED,
  561. 'value' => '1',
  562. ],
  563. ];
  564. $this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
  565. $defaultUserRecord = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
  566. $result = $this->invokePrivate($this->accountManager, 'addMissingDefaultValues', [$input, $defaultUserRecord]);
  567. $this->assertSame($expected, $result);
  568. }
  569. public function testGetAccount() {
  570. $accountManager = $this->getInstance(['getUser']);
  571. /** @var IUser $user */
  572. $user = $this->createMock(IUser::class);
  573. $data = [
  574. [
  575. 'value' => '@twitterhandle',
  576. 'scope' => IAccountManager::SCOPE_LOCAL,
  577. 'verified' => IAccountManager::NOT_VERIFIED,
  578. 'name' => IAccountManager::PROPERTY_TWITTER,
  579. ],
  580. [
  581. 'value' => 'test@example.com',
  582. 'scope' => IAccountManager::SCOPE_PUBLISHED,
  583. 'verified' => IAccountManager::VERIFICATION_IN_PROGRESS,
  584. 'name' => IAccountManager::PROPERTY_EMAIL,
  585. ],
  586. [
  587. 'value' => 'https://example.com',
  588. 'scope' => IAccountManager::SCOPE_FEDERATED,
  589. 'verified' => IAccountManager::VERIFIED,
  590. 'name' => IAccountManager::PROPERTY_WEBSITE,
  591. ],
  592. ];
  593. $expected = new Account($user);
  594. $expected->setProperty(IAccountManager::PROPERTY_TWITTER, '@twitterhandle', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
  595. $expected->setProperty(IAccountManager::PROPERTY_EMAIL, 'test@example.com', IAccountManager::SCOPE_PUBLISHED, IAccountManager::VERIFICATION_IN_PROGRESS);
  596. $expected->setProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_FEDERATED, IAccountManager::VERIFIED);
  597. $accountManager->expects($this->once())
  598. ->method('getUser')
  599. ->willReturn($data);
  600. $this->assertEquals($expected, $accountManager->getAccount($user));
  601. }
  602. public function dataParsePhoneNumber(): array {
  603. return [
  604. ['0711 / 25 24 28-90', 'DE', '+4971125242890'],
  605. ['0711 / 25 24 28-90', '', null],
  606. ['+49 711 / 25 24 28-90', '', '+4971125242890'],
  607. ];
  608. }
  609. /**
  610. * @dataProvider dataParsePhoneNumber
  611. */
  612. public function testParsePhoneNumber(string $phoneInput, string $defaultRegion, ?string $phoneNumber): void {
  613. $this->config->method('getSystemValueString')
  614. ->willReturn($defaultRegion);
  615. if ($phoneNumber === null) {
  616. $this->expectException(\InvalidArgumentException::class);
  617. self::invokePrivate($this->accountManager, 'parsePhoneNumber', [$phoneInput]);
  618. } else {
  619. self::assertEquals($phoneNumber, self::invokePrivate($this->accountManager, 'parsePhoneNumber', [$phoneInput]));
  620. }
  621. }
  622. public function dataParseWebsite(): array {
  623. return [
  624. ['https://nextcloud.com', 'https://nextcloud.com'],
  625. ['http://nextcloud.com', 'http://nextcloud.com'],
  626. ['ftp://nextcloud.com', null],
  627. ['//nextcloud.com/', null],
  628. ['https:///?query', null],
  629. ];
  630. }
  631. /**
  632. * @dataProvider dataParseWebsite
  633. * @param string $websiteInput
  634. * @param string|null $websiteOutput
  635. */
  636. public function testParseWebsite(string $websiteInput, ?string $websiteOutput): void {
  637. if ($websiteOutput === null) {
  638. $this->expectException(\InvalidArgumentException::class);
  639. self::invokePrivate($this->accountManager, 'parseWebsite', [$websiteInput]);
  640. } else {
  641. self::assertEquals($websiteOutput, self::invokePrivate($this->accountManager, 'parseWebsite', [$websiteInput]));
  642. }
  643. }
  644. /**
  645. * @dataProvider searchDataProvider
  646. */
  647. public function testSearchUsers(string $property, array $values, array $expected): void {
  648. $this->populateOrUpdate();
  649. $matchedUsers = $this->accountManager->searchUsers($property, $values);
  650. foreach ($expected as $expectedEntry) {
  651. $this->assertContains($expectedEntry, $matchedUsers);
  652. }
  653. if (empty($expected)) {
  654. $this->assertEmpty($matchedUsers);
  655. }
  656. }
  657. public function searchDataProvider(): array {
  658. return [
  659. [ #0 Search for an existing name
  660. IAccountManager::PROPERTY_DISPLAYNAME,
  661. ['Jane Doe'],
  662. ['Jane Doe' => 'j.doe']
  663. ],
  664. [ #1 Search for part of a name (no result)
  665. IAccountManager::PROPERTY_DISPLAYNAME,
  666. ['Jane'],
  667. []
  668. ],
  669. [ #2 Search for part of a name (no result, test wildcard)
  670. IAccountManager::PROPERTY_DISPLAYNAME,
  671. ['Jane%'],
  672. []
  673. ],
  674. [ #3 Search for phone
  675. IAccountManager::PROPERTY_PHONE,
  676. ['+491603121212'],
  677. ['+491603121212' => 'b32c5a5b-1084-4380-8856-e5223b16de9f'],
  678. ],
  679. [ #4 Search for twitter handles
  680. IAccountManager::PROPERTY_TWITTER,
  681. ['@sometwitter', '@a_alice', '@unseen'],
  682. ['@sometwitter' => 'j.doe', '@a_alice' => 'a.allison'],
  683. ],
  684. [ #5 Search for email
  685. IAccountManager::PROPERTY_EMAIL,
  686. ['cheng@emca.com'],
  687. ['cheng@emca.com' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
  688. ],
  689. [ #6 Search for email by additional email
  690. IAccountManager::PROPERTY_EMAIL,
  691. ['kai.cheng@emca.com'],
  692. ['kai.cheng@emca.com' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
  693. ],
  694. [ #7 Search for additional email
  695. IAccountManager::COLLECTION_EMAIL,
  696. ['kai.cheng@emca.com', 'cheng@emca.com'],
  697. ['kai.cheng@emca.com' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
  698. ],
  699. [ #8 Search for email by additional email (two valid search values, but the same user)
  700. IAccountManager::PROPERTY_EMAIL,
  701. ['kai.cheng@emca.com', 'cheng@emca.com'],
  702. [
  703. 'kai.cheng@emca.com' => '31b5316a-9b57-4b17-970a-315a4cbe73eb',
  704. ],
  705. ],
  706. ];
  707. }
  708. public function dataCheckEmailVerification(): array {
  709. return [
  710. [$this->makeUser('steve', 'Steve Smith', 'steve@steve.steve'), null],
  711. [$this->makeUser('emma', 'Emma Morales', 'emma@emma.com'), 'emma@morales.com'],
  712. [$this->makeUser('sarah@web.org', 'Sarah Foster', 'sarah@web.org'), null],
  713. [$this->makeUser('cole@web.org', 'Cole Harrison', 'cole@web.org'), 'cole@example.com'],
  714. [$this->makeUser('8d29e358-cf69-4849-bbf9-28076c0b908b', 'Alice McPherson', 'alice@example.com'), 'alice@mcpherson.com'],
  715. [$this->makeUser('11da2744-3f4d-4c17-8c13-4c057a379237', 'James Loranger', 'james@example.com'), ''],
  716. ];
  717. }
  718. /**
  719. * @dataProvider dataCheckEmailVerification
  720. */
  721. public function testCheckEmailVerification(IUser $user, ?string $newEmail): void {
  722. // Once because of getAccount, once because of getUser
  723. $this->config->expects($this->exactly(2))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
  724. $account = $this->accountManager->getAccount($user);
  725. $emailUpdated = false;
  726. if (!empty($newEmail)) {
  727. $account->getProperty(IAccountManager::PROPERTY_EMAIL)->setValue($newEmail);
  728. $emailUpdated = true;
  729. }
  730. if ($emailUpdated) {
  731. $this->jobList->expects($this->once())
  732. ->method('add')
  733. ->with(VerifyUserData::class);
  734. } else {
  735. $this->jobList->expects($this->never())
  736. ->method('add')
  737. ->with(VerifyUserData::class);
  738. }
  739. /** @var array $oldData */
  740. $oldData = $this->invokePrivate($this->accountManager, 'getUser', [$user, false]);
  741. $this->invokePrivate($this->accountManager, 'checkEmailVerification', [$account, $oldData]);
  742. }
  743. public function dataSetDefaultPropertyScopes(): array {
  744. return [
  745. [
  746. [],
  747. [
  748. IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
  749. IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL,
  750. IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED,
  751. IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_LOCAL,
  752. ]
  753. ],
  754. [
  755. [
  756. IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
  757. IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL,
  758. IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
  759. ], [
  760. IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
  761. IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL,
  762. IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
  763. ]
  764. ],
  765. [
  766. [
  767. IAccountManager::PROPERTY_ADDRESS => 'invalid scope',
  768. 'invalid property' => IAccountManager::SCOPE_LOCAL,
  769. IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
  770. ],
  771. [
  772. IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL,
  773. IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED,
  774. IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
  775. ]
  776. ],
  777. ];
  778. }
  779. /**
  780. * @dataProvider dataSetDefaultPropertyScopes
  781. */
  782. public function testSetDefaultPropertyScopes(array $propertyScopes, array $expectedResultScopes): void {
  783. $user = $this->makeUser('steve', 'Steve Smith', 'steve@steve.steve');
  784. $this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn($propertyScopes);
  785. $result = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
  786. $resultProperties = array_column($result, 'name');
  787. $this->assertEmpty(array_diff($resultProperties, IAccountManager::ALLOWED_PROPERTIES), "Building default user record returned non-allowed properties");
  788. foreach ($expectedResultScopes as $expectedResultScopeKey => $expectedResultScopeValue) {
  789. $resultScope = $result[array_search($expectedResultScopeKey, $resultProperties)]['scope'];
  790. $this->assertEquals($expectedResultScopeValue, $resultScope, "The result scope doesn't follow the value set into the config or defaults correctly.");
  791. }
  792. }
  793. }