ContactsStoreTest.php 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Tests\Contacts\ContactsMenu;
  8. use OC\Contacts\ContactsMenu\ContactsStore;
  9. use OC\KnownUser\KnownUserService;
  10. use OC\Profile\ProfileManager;
  11. use OCA\UserStatus\Db\UserStatus;
  12. use OCA\UserStatus\Service\StatusService;
  13. use OCP\Contacts\IManager;
  14. use OCP\IConfig;
  15. use OCP\IGroupManager;
  16. use OCP\IURLGenerator;
  17. use OCP\IUser;
  18. use OCP\IUserManager;
  19. use OCP\L10N\IFactory as IL10NFactory;
  20. use PHPUnit\Framework\MockObject\MockObject;
  21. use Test\TestCase;
  22. class ContactsStoreTest extends TestCase {
  23. private ContactsStore $contactsStore;
  24. private StatusService|MockObject $statusService;
  25. /** @var IManager|MockObject */
  26. private $contactsManager;
  27. /** @var ProfileManager */
  28. private $profileManager;
  29. /** @var IUserManager|MockObject */
  30. private $userManager;
  31. /** @var IURLGenerator */
  32. private $urlGenerator;
  33. /** @var IGroupManager|MockObject */
  34. private $groupManager;
  35. /** @var IConfig|MockObject */
  36. private $config;
  37. /** @var KnownUserService|MockObject */
  38. private $knownUserService;
  39. /** @var IL10NFactory */
  40. private $l10nFactory;
  41. protected function setUp(): void {
  42. parent::setUp();
  43. $this->contactsManager = $this->createMock(IManager::class);
  44. $this->statusService = $this->createMock(StatusService::class);
  45. $this->userManager = $this->createMock(IUserManager::class);
  46. $this->profileManager = $this->createMock(ProfileManager::class);
  47. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  48. $this->groupManager = $this->createMock(IGroupManager::class);
  49. $this->config = $this->createMock(IConfig::class);
  50. $this->knownUserService = $this->createMock(KnownUserService::class);
  51. $this->l10nFactory = $this->createMock(IL10NFactory::class);
  52. $this->contactsStore = new ContactsStore(
  53. $this->contactsManager,
  54. $this->statusService,
  55. $this->config,
  56. $this->profileManager,
  57. $this->userManager,
  58. $this->urlGenerator,
  59. $this->groupManager,
  60. $this->knownUserService,
  61. $this->l10nFactory,
  62. );
  63. }
  64. public function testGetContactsWithoutFilter() {
  65. /** @var IUser|MockObject $user */
  66. $user = $this->createMock(IUser::class);
  67. $this->contactsManager->expects($this->once())
  68. ->method('search')
  69. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  70. ->willReturn([
  71. [
  72. 'UID' => 123,
  73. ],
  74. [
  75. 'UID' => 567,
  76. 'FN' => 'Darren Roner',
  77. 'EMAIL' => [
  78. 'darren@roner.au'
  79. ],
  80. ],
  81. ]);
  82. $user->expects($this->exactly(2))
  83. ->method('getUID')
  84. ->willReturn('user123');
  85. $entries = $this->contactsStore->getContacts($user, '');
  86. $this->assertCount(2, $entries);
  87. $this->assertEquals([
  88. 'darren@roner.au'
  89. ], $entries[1]->getEMailAddresses());
  90. }
  91. public function testGetContactsHidesOwnEntry() {
  92. /** @var IUser|MockObject $user */
  93. $user = $this->createMock(IUser::class);
  94. $this->contactsManager->expects($this->once())
  95. ->method('search')
  96. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  97. ->willReturn([
  98. [
  99. 'UID' => 'user123',
  100. ],
  101. [
  102. 'UID' => 567,
  103. 'FN' => 'Darren Roner',
  104. 'EMAIL' => [
  105. 'darren@roner.au'
  106. ],
  107. ],
  108. ]);
  109. $user->expects($this->exactly(2))
  110. ->method('getUID')
  111. ->willReturn('user123');
  112. $entries = $this->contactsStore->getContacts($user, '');
  113. $this->assertCount(1, $entries);
  114. }
  115. public function testGetContactsWithoutBinaryImage() {
  116. /** @var IUser|MockObject $user */
  117. $user = $this->createMock(IUser::class);
  118. $this->urlGenerator->expects($this->any())
  119. ->method('linkToRouteAbsolute')
  120. ->with('core.GuestAvatar.getAvatar', $this->anything())
  121. ->willReturn('https://urlToNcAvatar.test');
  122. $this->contactsManager->expects($this->once())
  123. ->method('search')
  124. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  125. ->willReturn([
  126. [
  127. 'UID' => 123,
  128. ],
  129. [
  130. 'UID' => 567,
  131. 'FN' => 'Darren Roner',
  132. 'EMAIL' => [
  133. 'darren@roner.au'
  134. ],
  135. 'PHOTO' => base64_encode('photophotophoto'),
  136. ],
  137. ]);
  138. $user->expects($this->exactly(2))
  139. ->method('getUID')
  140. ->willReturn('user123');
  141. $entries = $this->contactsStore->getContacts($user, '');
  142. $this->assertCount(2, $entries);
  143. $this->assertSame('https://urlToNcAvatar.test', $entries[1]->getAvatar());
  144. }
  145. public function testGetContactsWithoutAvatarURI() {
  146. /** @var IUser|MockObject $user */
  147. $user = $this->createMock(IUser::class);
  148. $this->contactsManager->expects($this->once())
  149. ->method('search')
  150. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  151. ->willReturn([
  152. [
  153. 'UID' => 123,
  154. ],
  155. [
  156. 'UID' => 567,
  157. 'FN' => 'Darren Roner',
  158. 'EMAIL' => [
  159. 'darren@roner.au'
  160. ],
  161. 'PHOTO' => 'VALUE=uri:https://photo',
  162. ],
  163. ]);
  164. $user->expects($this->exactly(2))
  165. ->method('getUID')
  166. ->willReturn('user123');
  167. $entries = $this->contactsStore->getContacts($user, '');
  168. $this->assertCount(2, $entries);
  169. $this->assertEquals('https://photo', $entries[1]->getAvatar());
  170. }
  171. public function testGetContactsWhenUserIsInExcludeGroups() {
  172. $this->config
  173. ->method('getAppValue')
  174. ->willReturnMap([
  175. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  176. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no'],
  177. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'no'],
  178. ['core', 'shareapi_exclude_groups', 'no', 'yes'],
  179. ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
  180. ['core', 'shareapi_exclude_groups_list', '', '["group1", "group5", "group6"]'],
  181. ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
  182. ]);
  183. /** @var IUser|MockObject $currentUser */
  184. $currentUser = $this->createMock(IUser::class);
  185. $currentUser->expects($this->exactly(2))
  186. ->method('getUID')
  187. ->willReturn('user001');
  188. $this->groupManager->expects($this->once())
  189. ->method('getUserGroupIds')
  190. ->with($this->equalTo($currentUser))
  191. ->willReturn(['group1', 'group2', 'group3']);
  192. $this->contactsManager->expects($this->once())
  193. ->method('search')
  194. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  195. ->willReturn([
  196. [
  197. 'UID' => 'user123',
  198. 'isLocalSystemBook' => true
  199. ],
  200. [
  201. 'UID' => 'user12345',
  202. 'isLocalSystemBook' => true
  203. ],
  204. ]);
  205. $entries = $this->contactsStore->getContacts($currentUser, '');
  206. $this->assertCount(0, $entries);
  207. }
  208. public function testGetContactsOnlyShareIfInTheSameGroup() {
  209. $this->config
  210. ->method('getAppValue')
  211. ->willReturnMap([
  212. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  213. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no'],
  214. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'no'],
  215. ['core', 'shareapi_exclude_groups', 'no', 'no'],
  216. ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
  217. ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
  218. ]);
  219. /** @var IUser|MockObject $currentUser */
  220. $currentUser = $this->createMock(IUser::class);
  221. $currentUser->expects($this->exactly(2))
  222. ->method('getUID')
  223. ->willReturn('user001');
  224. $user1 = $this->createMock(IUser::class);
  225. $user2 = $this->createMock(IUser::class);
  226. $user3 = $this->createMock(IUser::class);
  227. $this->groupManager->expects($this->exactly(4))
  228. ->method('getUserGroupIds')
  229. ->withConsecutive(
  230. [$this->equalTo($currentUser)],
  231. [$this->equalTo($user1)],
  232. [$this->equalTo($user2)],
  233. [$this->equalTo($user3)]
  234. )
  235. ->willReturnOnConsecutiveCalls(
  236. ['group1', 'group2', 'group3'],
  237. ['group1'],
  238. ['group2', 'group3'],
  239. ['group8', 'group9']
  240. );
  241. $this->userManager->expects($this->exactly(3))
  242. ->method('get')
  243. ->withConsecutive(
  244. ['user1'],
  245. ['user2'],
  246. ['user3']
  247. )
  248. ->willReturnOnConsecutiveCalls($user1, $user2, $user3);
  249. $this->contactsManager->expects($this->once())
  250. ->method('search')
  251. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  252. ->willReturn([
  253. [
  254. 'UID' => 'user1',
  255. 'isLocalSystemBook' => true
  256. ],
  257. [
  258. 'UID' => 'user2',
  259. 'isLocalSystemBook' => true
  260. ],
  261. [
  262. 'UID' => 'user3',
  263. 'isLocalSystemBook' => true
  264. ],
  265. [
  266. 'UID' => 'contact',
  267. ],
  268. ]);
  269. $entries = $this->contactsStore->getContacts($currentUser, '');
  270. $this->assertCount(3, $entries);
  271. $this->assertEquals('user1', $entries[0]->getProperty('UID'));
  272. $this->assertEquals('user2', $entries[1]->getProperty('UID'));
  273. $this->assertEquals('contact', $entries[2]->getProperty('UID'));
  274. }
  275. public function testGetContactsOnlyEnumerateIfInTheSameGroup() {
  276. $this->config
  277. ->method('getAppValue')
  278. ->willReturnMap([
  279. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  280. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'yes'],
  281. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'no'],
  282. ['core', 'shareapi_exclude_groups', 'no', 'no'],
  283. ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
  284. ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
  285. ]);
  286. /** @var IUser|MockObject $currentUser */
  287. $currentUser = $this->createMock(IUser::class);
  288. $currentUser->expects($this->exactly(2))
  289. ->method('getUID')
  290. ->willReturn('user001');
  291. $user1 = $this->createMock(IUser::class);
  292. $user2 = $this->createMock(IUser::class);
  293. $user3 = $this->createMock(IUser::class);
  294. $this->groupManager->expects($this->exactly(4))
  295. ->method('getUserGroupIds')
  296. ->withConsecutive(
  297. [$this->equalTo($currentUser)],
  298. [$this->equalTo($user1)],
  299. [$this->equalTo($user2)],
  300. [$this->equalTo($user3)]
  301. )
  302. ->willReturnOnConsecutiveCalls(
  303. ['group1', 'group2', 'group3'],
  304. ['group1'],
  305. ['group2', 'group3'],
  306. ['group8', 'group9']
  307. );
  308. $this->userManager->expects($this->exactly(3))
  309. ->method('get')
  310. ->withConsecutive(
  311. ['user1'],
  312. ['user2'],
  313. ['user3']
  314. )
  315. ->willReturn($user1, $user2, $user3);
  316. $this->contactsManager->expects($this->once())
  317. ->method('search')
  318. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  319. ->willReturn([
  320. [
  321. 'UID' => 'user1',
  322. 'isLocalSystemBook' => true
  323. ],
  324. [
  325. 'UID' => 'user2',
  326. 'isLocalSystemBook' => true
  327. ],
  328. [
  329. 'UID' => 'user3',
  330. 'isLocalSystemBook' => true
  331. ],
  332. [
  333. 'UID' => 'contact',
  334. ],
  335. ]);
  336. $entries = $this->contactsStore->getContacts($currentUser, '');
  337. $this->assertCount(3, $entries);
  338. $this->assertEquals('user1', $entries[0]->getProperty('UID'));
  339. $this->assertEquals('user2', $entries[1]->getProperty('UID'));
  340. $this->assertEquals('contact', $entries[2]->getProperty('UID'));
  341. }
  342. public function testGetContactsOnlyEnumerateIfPhoneBookMatch() {
  343. $this->config
  344. ->method('getAppValue')
  345. ->willReturnMap([
  346. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  347. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no'],
  348. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'yes'],
  349. ['core', 'shareapi_exclude_groups', 'no', 'no'],
  350. ['core', 'shareapi_only_share_with_group_members', 'no', 'no'],
  351. ]);
  352. /** @var IUser|MockObject $currentUser */
  353. $currentUser = $this->createMock(IUser::class);
  354. $currentUser->expects($this->exactly(2))
  355. ->method('getUID')
  356. ->willReturn('user001');
  357. $this->groupManager->expects($this->once())
  358. ->method('getUserGroupIds')
  359. ->with($this->equalTo($currentUser))
  360. ->willReturn(['group1', 'group2', 'group3']);
  361. $this->knownUserService->method('isKnownToUser')
  362. ->willReturnMap([
  363. ['user001', 'user1', true],
  364. ['user001', 'user2', true],
  365. ['user001', 'user3', false],
  366. ]);
  367. $this->contactsManager->expects($this->once())
  368. ->method('search')
  369. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  370. ->willReturn([
  371. [
  372. 'UID' => 'user1',
  373. 'isLocalSystemBook' => true
  374. ],
  375. [
  376. 'UID' => 'user2',
  377. 'isLocalSystemBook' => true
  378. ],
  379. [
  380. 'UID' => 'user3',
  381. 'isLocalSystemBook' => true
  382. ],
  383. [
  384. 'UID' => 'contact',
  385. ],
  386. ]);
  387. $entries = $this->contactsStore->getContacts($currentUser, '');
  388. $this->assertCount(3, $entries);
  389. $this->assertEquals('user1', $entries[0]->getProperty('UID'));
  390. $this->assertEquals('user2', $entries[1]->getProperty('UID'));
  391. $this->assertEquals('contact', $entries[2]->getProperty('UID'));
  392. }
  393. public function testGetContactsOnlyEnumerateIfPhoneBookMatchWithOwnGroupsOnly() {
  394. $this->config
  395. ->method('getAppValue')
  396. ->willReturnMap([
  397. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  398. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no'],
  399. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'yes'],
  400. ['core', 'shareapi_exclude_groups', 'no', 'no'],
  401. ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
  402. ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
  403. ]);
  404. /** @var IUser|MockObject $currentUser */
  405. $currentUser = $this->createMock(IUser::class);
  406. $currentUser->expects($this->exactly(2))
  407. ->method('getUID')
  408. ->willReturn('user001');
  409. $user1 = $this->createMock(IUser::class);
  410. $user2 = $this->createMock(IUser::class);
  411. $user3 = $this->createMock(IUser::class);
  412. $this->groupManager->expects($this->exactly(4))
  413. ->method('getUserGroupIds')
  414. ->withConsecutive(
  415. [$this->equalTo($currentUser)],
  416. [$this->equalTo($user1)],
  417. [$this->equalTo($user2)],
  418. [$this->equalTo($user3)]
  419. )
  420. ->willReturnOnConsecutiveCalls(
  421. ['group1', 'group2', 'group3'],
  422. ['group1'],
  423. ['group2', 'group3'],
  424. ['group8', 'group9']
  425. );
  426. $this->userManager->expects($this->exactly(3))
  427. ->method('get')
  428. ->withConsecutive(
  429. ['user1'],
  430. ['user2'],
  431. ['user3']
  432. )
  433. ->willReturnOnConsecutiveCalls($user1, $user2, $user3);
  434. $this->knownUserService->method('isKnownToUser')
  435. ->willReturnMap([
  436. ['user001', 'user1', true],
  437. ['user001', 'user2', true],
  438. ['user001', 'user3', true],
  439. ]);
  440. $this->contactsManager->expects($this->once())
  441. ->method('search')
  442. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  443. ->willReturn([
  444. [
  445. 'UID' => 'user1',
  446. 'isLocalSystemBook' => true
  447. ],
  448. [
  449. 'UID' => 'user2',
  450. 'isLocalSystemBook' => true
  451. ],
  452. [
  453. 'UID' => 'user3',
  454. 'isLocalSystemBook' => true
  455. ],
  456. [
  457. 'UID' => 'contact',
  458. ],
  459. ]);
  460. $entries = $this->contactsStore->getContacts($currentUser, '');
  461. $this->assertCount(3, $entries);
  462. $this->assertEquals('user1', $entries[0]->getProperty('UID'));
  463. $this->assertEquals('user2', $entries[1]->getProperty('UID'));
  464. $this->assertEquals('contact', $entries[2]->getProperty('UID'));
  465. }
  466. public function testGetContactsOnlyEnumerateIfPhoneBookOrSameGroup() {
  467. $this->config
  468. ->method('getAppValue')
  469. ->willReturnMap([
  470. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  471. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'yes'],
  472. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'yes'],
  473. ['core', 'shareapi_exclude_groups', 'no', 'no'],
  474. ['core', 'shareapi_only_share_with_group_members', 'no', 'no'],
  475. ]);
  476. /** @var IUser|MockObject $currentUser */
  477. $currentUser = $this->createMock(IUser::class);
  478. $currentUser->expects($this->exactly(2))
  479. ->method('getUID')
  480. ->willReturn('user001');
  481. $user1 = $this->createMock(IUser::class);
  482. $this->groupManager->expects($this->exactly(2))
  483. ->method('getUserGroupIds')
  484. ->withConsecutive(
  485. [$this->equalTo($currentUser)],
  486. [$this->equalTo($user1)]
  487. )
  488. ->willReturnOnConsecutiveCalls(
  489. ['group1', 'group2', 'group3'],
  490. ['group1']
  491. );
  492. $this->userManager->expects($this->once())
  493. ->method('get')
  494. ->with('user1')
  495. ->willReturn($user1);
  496. $this->knownUserService->method('isKnownToUser')
  497. ->willReturnMap([
  498. ['user001', 'user1', false],
  499. ['user001', 'user2', true],
  500. ['user001', 'user3', true],
  501. ]);
  502. $this->contactsManager->expects($this->once())
  503. ->method('search')
  504. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  505. ->willReturn([
  506. [
  507. 'UID' => 'user1',
  508. 'isLocalSystemBook' => true
  509. ],
  510. [
  511. 'UID' => 'user2',
  512. 'isLocalSystemBook' => true
  513. ],
  514. [
  515. 'UID' => 'user3',
  516. 'isLocalSystemBook' => true
  517. ],
  518. [
  519. 'UID' => 'contact',
  520. ],
  521. ]);
  522. $entries = $this->contactsStore->getContacts($currentUser, '');
  523. $this->assertCount(4, $entries);
  524. $this->assertEquals('user1', $entries[0]->getProperty('UID'));
  525. $this->assertEquals('user2', $entries[1]->getProperty('UID'));
  526. $this->assertEquals('user3', $entries[2]->getProperty('UID'));
  527. $this->assertEquals('contact', $entries[3]->getProperty('UID'));
  528. }
  529. public function testGetContactsOnlyEnumerateIfPhoneBookOrSameGroupInOwnGroupsOnly() {
  530. $this->config
  531. ->method('getAppValue')
  532. ->willReturnMap([
  533. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  534. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'yes'],
  535. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'yes'],
  536. ['core', 'shareapi_exclude_groups', 'no', 'no'],
  537. ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
  538. ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
  539. ]);
  540. /** @var IUser|MockObject $currentUser */
  541. $currentUser = $this->createMock(IUser::class);
  542. $currentUser->expects($this->exactly(2))
  543. ->method('getUID')
  544. ->willReturn('user001');
  545. $user1 = $this->createMock(IUser::class);
  546. $user2 = $this->createMock(IUser::class);
  547. $user3 = $this->createMock(IUser::class);
  548. $this->groupManager->expects($this->exactly(4))
  549. ->method('getUserGroupIds')
  550. ->withConsecutive(
  551. [$this->equalTo($currentUser)],
  552. [$this->equalTo($user1)],
  553. [$this->equalTo($user2)],
  554. [$this->equalTo($user3)]
  555. )
  556. ->willReturnOnConsecutiveCalls(
  557. ['group1', 'group2', 'group3'],
  558. ['group1'],
  559. ['group2', 'group3'],
  560. ['group8', 'group9']
  561. );
  562. $this->userManager->expects($this->exactly(3))
  563. ->method('get')
  564. ->withConsecutive(
  565. ['user1'],
  566. ['user2'],
  567. ['user3']
  568. )
  569. ->willReturnOnConsecutiveCalls($user1, $user2, $user3);
  570. $this->knownUserService->method('isKnownToUser')
  571. ->willReturnMap([
  572. ['user001', 'user1', false],
  573. ['user001', 'user2', true],
  574. ['user001', 'user3', true],
  575. ]);
  576. $this->contactsManager->expects($this->once())
  577. ->method('search')
  578. ->with($this->equalTo(''), $this->equalTo(['FN', 'EMAIL']))
  579. ->willReturn([
  580. [
  581. 'UID' => 'user1',
  582. 'isLocalSystemBook' => true
  583. ],
  584. [
  585. 'UID' => 'user2',
  586. 'isLocalSystemBook' => true
  587. ],
  588. [
  589. 'UID' => 'user3',
  590. 'isLocalSystemBook' => true
  591. ],
  592. [
  593. 'UID' => 'contact',
  594. ],
  595. ]);
  596. $entries = $this->contactsStore->getContacts($currentUser, '');
  597. $this->assertCount(3, $entries);
  598. $this->assertEquals('user1', $entries[0]->getProperty('UID'));
  599. $this->assertEquals('user2', $entries[1]->getProperty('UID'));
  600. $this->assertEquals('contact', $entries[2]->getProperty('UID'));
  601. }
  602. public function testGetContactsWithFilter() {
  603. $this->config
  604. ->method('getAppValue')
  605. ->willReturnMap([
  606. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'no'],
  607. ['core', 'shareapi_restrict_user_enumeration_full_match', 'yes', 'yes'],
  608. ]);
  609. /** @var IUser|MockObject $user */
  610. $user = $this->createMock(IUser::class);
  611. $this->contactsManager->expects($this->any())
  612. ->method('search')
  613. ->willReturn([
  614. [
  615. 'UID' => 'a567',
  616. 'FN' => 'Darren Roner',
  617. 'EMAIL' => [
  618. 'darren@roner.au',
  619. ],
  620. 'isLocalSystemBook' => true,
  621. ],
  622. [
  623. 'UID' => 'john',
  624. 'FN' => 'John Doe',
  625. 'EMAIL' => [
  626. 'john@example.com',
  627. ],
  628. 'isLocalSystemBook' => true,
  629. ],
  630. [
  631. 'FN' => 'Anne D',
  632. 'EMAIL' => [
  633. 'anne@example.com',
  634. ],
  635. 'isLocalSystemBook' => false,
  636. ],
  637. ]);
  638. $user->expects($this->any())
  639. ->method('getUID')
  640. ->willReturn('user123');
  641. // Complete match on UID should match
  642. $entry = $this->contactsStore->getContacts($user, 'a567');
  643. $this->assertSame(2, count($entry));
  644. $this->assertEquals([
  645. 'darren@roner.au'
  646. ], $entry[0]->getEMailAddresses());
  647. // Partial match on UID should not match
  648. $entry = $this->contactsStore->getContacts($user, 'a56');
  649. $this->assertSame(1, count($entry));
  650. $this->assertEquals([
  651. 'anne@example.com'
  652. ], $entry[0]->getEMailAddresses());
  653. // Complete match on email should match
  654. $entry = $this->contactsStore->getContacts($user, 'john@example.com');
  655. $this->assertSame(2, count($entry));
  656. $this->assertEquals([
  657. 'john@example.com'
  658. ], $entry[0]->getEMailAddresses());
  659. $this->assertEquals([
  660. 'anne@example.com'
  661. ], $entry[1]->getEMailAddresses());
  662. // Partial match on email should not match
  663. $entry = $this->contactsStore->getContacts($user, 'john@example.co');
  664. $this->assertSame(1, count($entry));
  665. $this->assertEquals([
  666. 'anne@example.com'
  667. ], $entry[0]->getEMailAddresses());
  668. // Match on FN should not match
  669. $entry = $this->contactsStore->getContacts($user, 'Darren Roner');
  670. $this->assertSame(1, count($entry));
  671. $this->assertEquals([
  672. 'anne@example.com'
  673. ], $entry[0]->getEMailAddresses());
  674. // Don't filter users in local addressbook
  675. $entry = $this->contactsStore->getContacts($user, 'Anne D');
  676. $this->assertSame(1, count($entry));
  677. $this->assertEquals([
  678. 'anne@example.com'
  679. ], $entry[0]->getEMailAddresses());
  680. }
  681. public function testGetContactsWithFilterWithoutFullMatch() {
  682. $this->config
  683. ->method('getAppValue')
  684. ->willReturnMap([
  685. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'no'],
  686. ['core', 'shareapi_restrict_user_enumeration_full_match', 'yes', 'no'],
  687. ]);
  688. /** @var IUser|MockObject $user */
  689. $user = $this->createMock(IUser::class);
  690. $this->contactsManager->expects($this->any())
  691. ->method('search')
  692. ->willReturn([
  693. [
  694. 'UID' => 'a567',
  695. 'FN' => 'Darren Roner',
  696. 'EMAIL' => [
  697. 'darren@roner.au',
  698. ],
  699. 'isLocalSystemBook' => true,
  700. ],
  701. [
  702. 'UID' => 'john',
  703. 'FN' => 'John Doe',
  704. 'EMAIL' => [
  705. 'john@example.com',
  706. ],
  707. 'isLocalSystemBook' => true,
  708. ],
  709. [
  710. 'FN' => 'Anne D',
  711. 'EMAIL' => [
  712. 'anne@example.com',
  713. ],
  714. 'isLocalSystemBook' => false,
  715. ],
  716. ]);
  717. $user->expects($this->any())
  718. ->method('getUID')
  719. ->willReturn('user123');
  720. // Complete match on UID should not match
  721. $entry = $this->contactsStore->getContacts($user, 'a567');
  722. $this->assertSame(1, count($entry));
  723. $this->assertEquals([
  724. 'anne@example.com'
  725. ], $entry[0]->getEMailAddresses());
  726. // Partial match on UID should not match
  727. $entry = $this->contactsStore->getContacts($user, 'a56');
  728. $this->assertSame(1, count($entry));
  729. $this->assertEquals([
  730. 'anne@example.com'
  731. ], $entry[0]->getEMailAddresses());
  732. // Complete match on email should not match
  733. $entry = $this->contactsStore->getContacts($user, 'john@example.com');
  734. $this->assertSame(1, count($entry));
  735. $this->assertEquals([
  736. 'anne@example.com'
  737. ], $entry[0]->getEMailAddresses());
  738. // Partial match on email should not match
  739. $entry = $this->contactsStore->getContacts($user, 'john@example.co');
  740. $this->assertSame(1, count($entry));
  741. $this->assertEquals([
  742. 'anne@example.com'
  743. ], $entry[0]->getEMailAddresses());
  744. // Match on FN should not match
  745. $entry = $this->contactsStore->getContacts($user, 'Darren Roner');
  746. $this->assertSame(1, count($entry));
  747. $this->assertEquals([
  748. 'anne@example.com'
  749. ], $entry[0]->getEMailAddresses());
  750. // Don't filter users in local addressbook
  751. $entry = $this->contactsStore->getContacts($user, 'Anne D');
  752. $this->assertSame(1, count($entry));
  753. $this->assertEquals([
  754. 'anne@example.com'
  755. ], $entry[0]->getEMailAddresses());
  756. }
  757. public function testFindOneUser() {
  758. $this->config
  759. ->method('getAppValue')
  760. ->willReturnMap([
  761. ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
  762. ['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no'],
  763. ['core', 'shareapi_restrict_user_enumeration_to_phone', 'no', 'no'],
  764. ['core', 'shareapi_restrict_user_enumeration_full_match', 'yes', 'yes'],
  765. ['core', 'shareapi_exclude_groups', 'no', 'yes'],
  766. ['core', 'shareapi_exclude_groups_list', '', ''],
  767. ['core', 'shareapi_only_share_with_group_members', 'no', 'no'],
  768. ]);
  769. /** @var IUser|MockObject $user */
  770. $user = $this->createMock(IUser::class);
  771. $this->contactsManager->expects($this->once())
  772. ->method('search')
  773. ->with($this->equalTo('a567'), $this->equalTo(['UID']))
  774. ->willReturn([
  775. [
  776. 'UID' => 123,
  777. 'isLocalSystemBook' => false
  778. ],
  779. [
  780. 'UID' => 'a567',
  781. 'FN' => 'Darren Roner',
  782. 'EMAIL' => [
  783. 'darren@roner.au'
  784. ],
  785. 'isLocalSystemBook' => true
  786. ],
  787. ]);
  788. $user->expects($this->any())
  789. ->method('getUID')
  790. ->willReturn('user123');
  791. $entry = $this->contactsStore->findOne($user, 0, 'a567');
  792. $this->assertEquals([
  793. 'darren@roner.au'
  794. ], $entry->getEMailAddresses());
  795. }
  796. public function testFindOneEMail() {
  797. /** @var IUser|MockObject $user */
  798. $user = $this->createMock(IUser::class);
  799. $this->contactsManager->expects($this->once())
  800. ->method('search')
  801. ->with($this->equalTo('darren@roner.au'), $this->equalTo(['EMAIL']))
  802. ->willReturn([
  803. [
  804. 'UID' => 123,
  805. 'isLocalSystemBook' => false
  806. ],
  807. [
  808. 'UID' => 'a567',
  809. 'FN' => 'Darren Roner',
  810. 'EMAIL' => [
  811. 'darren@roner.au'
  812. ],
  813. 'isLocalSystemBook' => false
  814. ],
  815. ]);
  816. $user->expects($this->any())
  817. ->method('getUID')
  818. ->willReturn('user123');
  819. $entry = $this->contactsStore->findOne($user, 4, 'darren@roner.au');
  820. $this->assertEquals([
  821. 'darren@roner.au'
  822. ], $entry->getEMailAddresses());
  823. }
  824. public function testFindOneNotSupportedType() {
  825. /** @var IUser|MockObject $user */
  826. $user = $this->createMock(IUser::class);
  827. $entry = $this->contactsStore->findOne($user, 42, 'darren@roner.au');
  828. $this->assertEquals(null, $entry);
  829. }
  830. public function testFindOneNoMatches() {
  831. /** @var IUser|MockObject $user */
  832. $user = $this->createMock(IUser::class);
  833. $this->contactsManager->expects($this->once())
  834. ->method('search')
  835. ->with($this->equalTo('a567'), $this->equalTo(['UID']))
  836. ->willReturn([
  837. [
  838. 'UID' => 123,
  839. 'isLocalSystemBook' => false
  840. ],
  841. [
  842. 'UID' => 'a567',
  843. 'FN' => 'Darren Roner',
  844. 'EMAIL' => [
  845. 'darren@roner.au123'
  846. ],
  847. 'isLocalSystemBook' => false
  848. ],
  849. ]);
  850. $user->expects($this->never())
  851. ->method('getUID');
  852. $entry = $this->contactsStore->findOne($user, 0, 'a567');
  853. $this->assertEquals(null, $entry);
  854. }
  855. public function testGetRecentStatusFirst(): void {
  856. $user = $this->createMock(IUser::class);
  857. $status1 = new UserStatus();
  858. $status1->setUserId('user1');
  859. $status2 = new UserStatus();
  860. $status2->setUserId('user2');
  861. $this->statusService->expects(self::once())
  862. ->method('findAllRecentStatusChanges')
  863. ->willReturn([
  864. $status1,
  865. $status2,
  866. ]);
  867. $user1 = $this->createMock(IUser::class);
  868. $user1->method('getCloudId')->willReturn('user1@localcloud');
  869. $user2 = $this->createMock(IUser::class);
  870. $user2->method('getCloudId')->willReturn('user2@localcloud');
  871. $this->userManager->expects(self::exactly(2))
  872. ->method('get')
  873. ->willReturnCallback(function ($uid) use ($user1, $user2) {
  874. return match ($uid) {
  875. 'user1' => $user1,
  876. 'user2' => $user2,
  877. };
  878. });
  879. $this->contactsManager
  880. ->expects(self::exactly(3))
  881. ->method('search')
  882. ->willReturnCallback(function ($uid, $searchProps, $options) {
  883. return match ([$uid, $options['limit'] ?? null]) {
  884. ['user1@localcloud', 1] => [
  885. [
  886. 'UID' => 'user1',
  887. 'URI' => 'user1.vcf',
  888. ],
  889. ],
  890. ['user2@localcloud' => [], 1], // Simulate not found
  891. ['', 4] => [
  892. [
  893. 'UID' => 'contact1',
  894. 'URI' => 'contact1.vcf',
  895. ],
  896. [
  897. 'UID' => 'contact2',
  898. 'URI' => 'contact2.vcf',
  899. ],
  900. ],
  901. default => [],
  902. };
  903. });
  904. $contacts = $this->contactsStore->getContacts(
  905. $user,
  906. null,
  907. 5,
  908. );
  909. self::assertCount(3, $contacts);
  910. self::assertEquals('user1', $contacts[0]->getProperty('UID'));
  911. self::assertEquals('contact1', $contacts[1]->getProperty('UID'));
  912. self::assertEquals('contact2', $contacts[2]->getProperty('UID'));
  913. }
  914. public function testPaginateRecentStatus(): void {
  915. $user = $this->createMock(IUser::class);
  916. $status1 = new UserStatus();
  917. $status1->setUserId('user1');
  918. $status2 = new UserStatus();
  919. $status2->setUserId('user2');
  920. $status3 = new UserStatus();
  921. $status3->setUserId('user3');
  922. $this->statusService->expects(self::never())
  923. ->method('findAllRecentStatusChanges');
  924. $this->contactsManager
  925. ->expects(self::exactly(2))
  926. ->method('search')
  927. ->willReturnCallback(function ($uid, $searchProps, $options) {
  928. return match ([$uid, $options['limit'] ?? null, $options['offset'] ?? null]) {
  929. ['', 2, 0] => [
  930. [
  931. 'UID' => 'contact1',
  932. 'URI' => 'contact1.vcf',
  933. ],
  934. [
  935. 'UID' => 'contact2',
  936. 'URI' => 'contact2.vcf',
  937. ],
  938. ],
  939. ['', 2, 3] => [
  940. [
  941. 'UID' => 'contact3',
  942. 'URI' => 'contact3.vcf',
  943. ],
  944. ],
  945. default => [],
  946. };
  947. });
  948. $page1 = $this->contactsStore->getContacts(
  949. $user,
  950. null,
  951. 2,
  952. 0,
  953. );
  954. $page2 = $this->contactsStore->getContacts(
  955. $user,
  956. null,
  957. 2,
  958. 3,
  959. );
  960. self::assertCount(2, $page1);
  961. self::assertCount(1, $page2);
  962. }
  963. }