AbstractPrincipalBackendTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2018, Georg Ehrke
  4. *
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Georg Ehrke <oc.list@georgehrke.com>
  7. * @author Roeland Jago Douma <roeland@famdouma.nl>
  8. *
  9. * @license GNU AGPL version 3 or any later version
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License as
  13. * published by the Free Software Foundation, either version 3 of the
  14. * License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. *
  24. */
  25. namespace OCA\DAV\Tests\unit\CalDAV\ResourceBooking;
  26. use OCA\DAV\CalDAV\Proxy\Proxy;
  27. use OCA\DAV\CalDAV\Proxy\ProxyMapper;
  28. use OCP\IGroupManager;
  29. use OCP\ILogger;
  30. use OCP\IUser;
  31. use OCP\IUserSession;
  32. use Sabre\DAV\PropPatch;
  33. use Test\TestCase;
  34. abstract class AbstractPrincipalBackendTest extends TestCase {
  35. /** @var \OCA\DAV\CalDAV\ResourceBooking\ResourcePrincipalBackend|\OCA\DAV\CalDAV\ResourceBooking\RoomPrincipalBackend */
  36. protected $principalBackend;
  37. /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
  38. protected $userSession;
  39. /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
  40. protected $groupManager;
  41. /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
  42. protected $logger;
  43. /** @var ProxyMapper|\PHPUnit_Framework_MockObject_MockObject */
  44. protected $proxyMapper;
  45. /** @var string */
  46. protected $mainDbTable;
  47. /** @var string */
  48. protected $metadataDbTable;
  49. /** @var string */
  50. protected $foreignKey;
  51. /** @var string */
  52. protected $principalPrefix;
  53. /** @var string */
  54. protected $expectedCUType;
  55. protected function setUp(): void {
  56. parent::setUp();
  57. $this->userSession = $this->createMock(IUserSession::class);
  58. $this->groupManager = $this->createMock(IGroupManager::class);
  59. $this->logger = $this->createMock(ILogger::class);
  60. $this->proxyMapper = $this->createMock(ProxyMapper::class);
  61. }
  62. protected function tearDown(): void {
  63. $query = self::$realDatabase->getQueryBuilder();
  64. $query->delete('calendar_resources')->execute();
  65. $query->delete('calendar_resources_md')->execute();
  66. $query->delete('calendar_rooms')->execute();
  67. $query->delete('calendar_rooms_md')->execute();
  68. }
  69. public function testGetPrincipalsByPrefix() {
  70. $actual = $this->principalBackend->getPrincipalsByPrefix($this->principalPrefix);
  71. $this->assertEquals([
  72. [
  73. 'uri' => $this->principalPrefix . '/backend1-res1',
  74. '{DAV:}displayname' => 'Beamer1',
  75. '{http://sabredav.org/ns}email-address' => 'res1@foo.bar',
  76. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  77. ],
  78. [
  79. 'uri' => $this->principalPrefix . '/backend1-res2',
  80. '{DAV:}displayname' => 'TV1',
  81. '{http://sabredav.org/ns}email-address' => 'res2@foo.bar',
  82. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  83. ],
  84. [
  85. 'uri' => $this->principalPrefix . '/backend2-res3',
  86. '{DAV:}displayname' => 'Beamer2',
  87. '{http://sabredav.org/ns}email-address' => 'res3@foo.bar',
  88. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  89. '{http://nextcloud.com/ns}foo' => 'value1',
  90. '{http://nextcloud.com/ns}meta2' => 'value2',
  91. ],
  92. [
  93. 'uri' => $this->principalPrefix . '/backend2-res4',
  94. '{DAV:}displayname' => 'TV2',
  95. '{http://sabredav.org/ns}email-address' => 'res4@foo.bar',
  96. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  97. '{http://nextcloud.com/ns}meta1' => 'value1',
  98. '{http://nextcloud.com/ns}meta3' => 'value3-old',
  99. ],
  100. [
  101. 'uri' => $this->principalPrefix . '/backend3-res5',
  102. '{DAV:}displayname' => 'Beamer3',
  103. '{http://sabredav.org/ns}email-address' => 'res5@foo.bar',
  104. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  105. ],
  106. [
  107. 'uri' => $this->principalPrefix . '/backend3-res6',
  108. '{DAV:}displayname' => 'Pointer',
  109. '{http://sabredav.org/ns}email-address' => 'res6@foo.bar',
  110. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  111. '{http://nextcloud.com/ns}meta99' => 'value99'
  112. ]
  113. ], $actual);
  114. }
  115. public function testGetNoPrincipalsByPrefixForWrongPrincipalPrefix() {
  116. $actual = $this->principalBackend->getPrincipalsByPrefix('principals/users');
  117. $this->assertEquals([], $actual);
  118. }
  119. public function testGetPrincipalByPath() {
  120. $actual = $this->principalBackend->getPrincipalByPath($this->principalPrefix . '/backend2-res3');
  121. $this->assertEquals([
  122. 'uri' => $this->principalPrefix . '/backend2-res3',
  123. '{DAV:}displayname' => 'Beamer2',
  124. '{http://sabredav.org/ns}email-address' => 'res3@foo.bar',
  125. '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->expectedCUType,
  126. '{http://nextcloud.com/ns}foo' => 'value1',
  127. '{http://nextcloud.com/ns}meta2' => 'value2',
  128. ], $actual);
  129. }
  130. public function testGetPrincipalByPathNotFound() {
  131. $actual = $this->principalBackend->getPrincipalByPath($this->principalPrefix . '/db-123');
  132. $this->assertEquals(null, $actual);
  133. }
  134. public function testGetPrincipalByPathWrongPrefix() {
  135. $actual = $this->principalBackend->getPrincipalByPath('principals/users/foo-bar');
  136. $this->assertEquals(null, $actual);
  137. }
  138. public function testGetGroupMemberSet() {
  139. $actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/backend1-res1');
  140. $this->assertEquals([], $actual);
  141. }
  142. public function testGetGroupMemberSetProxyRead() {
  143. $proxy1 = new Proxy();
  144. $proxy1->setProxyId('proxyId1');
  145. $proxy1->setPermissions(1);
  146. $proxy2 = new Proxy();
  147. $proxy2->setProxyId('proxyId2');
  148. $proxy2->setPermissions(3);
  149. $proxy3 = new Proxy();
  150. $proxy3->setProxyId('proxyId3');
  151. $proxy3->setPermissions(3);
  152. $this->proxyMapper->expects($this->once())
  153. ->method('getProxiesOf')
  154. ->with($this->principalPrefix . '/backend1-res1')
  155. ->willReturn([$proxy1, $proxy2, $proxy3]);
  156. $actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/backend1-res1/calendar-proxy-read');
  157. $this->assertEquals(['proxyId1'], $actual);
  158. }
  159. public function testGetGroupMemberSetProxyWrite() {
  160. $proxy1 = new Proxy();
  161. $proxy1->setProxyId('proxyId1');
  162. $proxy1->setPermissions(1);
  163. $proxy2 = new Proxy();
  164. $proxy2->setProxyId('proxyId2');
  165. $proxy2->setPermissions(3);
  166. $proxy3 = new Proxy();
  167. $proxy3->setProxyId('proxyId3');
  168. $proxy3->setPermissions(3);
  169. $this->proxyMapper->expects($this->once())
  170. ->method('getProxiesOf')
  171. ->with($this->principalPrefix . '/backend1-res1')
  172. ->willReturn([$proxy1, $proxy2, $proxy3]);
  173. $actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/backend1-res1/calendar-proxy-write');
  174. $this->assertEquals(['proxyId2', 'proxyId3'], $actual);
  175. }
  176. public function testGetGroupMembership() {
  177. $proxy1 = new Proxy();
  178. $proxy1->setOwnerId('proxyId1');
  179. $proxy1->setPermissions(1);
  180. $proxy2 = new Proxy();
  181. $proxy2->setOwnerId('proxyId2');
  182. $proxy2->setPermissions(3);
  183. $this->proxyMapper->expects($this->once())
  184. ->method('getProxiesFor')
  185. ->with($this->principalPrefix . '/backend1-res1')
  186. ->willReturn([$proxy1, $proxy2]);
  187. $actual = $this->principalBackend->getGroupMembership($this->principalPrefix . '/backend1-res1');
  188. $this->assertEquals(['proxyId1/calendar-proxy-read', 'proxyId2/calendar-proxy-write'], $actual);
  189. }
  190. public function testSetGroupMemberSet() {
  191. $this->proxyMapper->expects($this->at(0))
  192. ->method('getProxiesOf')
  193. ->with($this->principalPrefix . '/backend1-res1')
  194. ->willReturn([]);
  195. $this->proxyMapper->expects($this->at(1))
  196. ->method('insert')
  197. ->with($this->callback(function ($proxy) {
  198. /** @var Proxy $proxy */
  199. if ($proxy->getOwnerId() !== $this->principalPrefix . '/backend1-res1') {
  200. return false;
  201. }
  202. if ($proxy->getProxyId() !== $this->principalPrefix . '/backend1-res2') {
  203. return false;
  204. }
  205. if ($proxy->getPermissions() !== 3) {
  206. return false;
  207. }
  208. return true;
  209. }));
  210. $this->proxyMapper->expects($this->at(2))
  211. ->method('insert')
  212. ->with($this->callback(function ($proxy) {
  213. /** @var Proxy $proxy */
  214. if ($proxy->getOwnerId() !== $this->principalPrefix . '/backend1-res1') {
  215. return false;
  216. }
  217. if ($proxy->getProxyId() !== $this->principalPrefix . '/backend2-res3') {
  218. return false;
  219. }
  220. if ($proxy->getPermissions() !== 3) {
  221. return false;
  222. }
  223. return true;
  224. }));
  225. $this->principalBackend->setGroupMemberSet($this->principalPrefix . '/backend1-res1/calendar-proxy-write', [$this->principalPrefix . '/backend1-res2', $this->principalPrefix . '/backend2-res3']);
  226. }
  227. public function testUpdatePrincipal() {
  228. $propPatch = $this->createMock(PropPatch::class);
  229. $actual = $this->principalBackend->updatePrincipal($this->principalPrefix . '/foo-bar', $propPatch);
  230. $this->assertEquals(0, $actual);
  231. }
  232. /**
  233. * @dataProvider dataSearchPrincipals
  234. */
  235. public function testSearchPrincipals($expected, $test) {
  236. $user = $this->createMock(IUser::class);
  237. $this->userSession->expects($this->once())
  238. ->method('getUser')
  239. ->with()
  240. ->willReturn($user);
  241. $this->groupManager->expects($this->once())
  242. ->method('getUserGroupIds')
  243. ->with($user)
  244. ->willReturn(['group1', 'group2']);
  245. $actual = $this->principalBackend->searchPrincipals($this->principalPrefix, [
  246. '{http://sabredav.org/ns}email-address' => 'foo',
  247. '{DAV:}displayname' => 'Beamer',
  248. ], $test);
  249. $this->assertEquals(
  250. str_replace('%prefix%', $this->principalPrefix, $expected),
  251. $actual);
  252. }
  253. public function dataSearchPrincipals() {
  254. // data providers are called before we subclass
  255. // this class, $this->principalPrefix is null
  256. // at that point, so we need this hack
  257. return [
  258. [[
  259. '%prefix%/backend1-res1',
  260. '%prefix%/backend2-res3',
  261. ], 'allof'],
  262. [[
  263. '%prefix%/backend1-res1',
  264. '%prefix%/backend1-res2',
  265. '%prefix%/backend2-res3',
  266. '%prefix%/backend2-res4',
  267. '%prefix%/backend3-res6',
  268. ], 'anyof'],
  269. ];
  270. }
  271. public function testSearchPrincipalsByMetadataKey() {
  272. $user = $this->createMock(IUser::class);
  273. $this->userSession->expects($this->once())
  274. ->method('getUser')
  275. ->with()
  276. ->willReturn($user);
  277. $this->groupManager->expects($this->once())
  278. ->method('getUserGroupIds')
  279. ->with($user)
  280. ->willReturn(['group1', 'group2']);
  281. $actual = $this->principalBackend->searchPrincipals($this->principalPrefix, [
  282. '{http://nextcloud.com/ns}meta3' => 'value',
  283. ]);
  284. $this->assertEquals([
  285. $this->principalPrefix . '/backend2-res4',
  286. ], $actual);
  287. }
  288. public function testSearchPrincipalsByCalendarUserAddressSet() {
  289. $user = $this->createMock(IUser::class);
  290. $this->userSession->method('getUser')
  291. ->with()
  292. ->willReturn($user);
  293. $this->groupManager->method('getUserGroupIds')
  294. ->with($user)
  295. ->willReturn(['group1', 'group2']);
  296. $actual = $this->principalBackend->searchPrincipals($this->principalPrefix, [
  297. '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set' => 'res2@foo.bar',
  298. ]);
  299. $this->assertEquals(
  300. str_replace('%prefix%', $this->principalPrefix, [
  301. '%prefix%/backend1-res2',
  302. ]),
  303. $actual);
  304. }
  305. public function testSearchPrincipalsEmptySearchProperties() {
  306. $this->userSession->expects($this->never())
  307. ->method('getUser');
  308. $this->groupManager->expects($this->never())
  309. ->method('getUserGroupIds');
  310. $this->principalBackend->searchPrincipals($this->principalPrefix, []);
  311. }
  312. public function testSearchPrincipalsWrongPrincipalPrefix() {
  313. $this->userSession->expects($this->never())
  314. ->method('getUser');
  315. $this->groupManager->expects($this->never())
  316. ->method('getUserGroupIds');
  317. $this->principalBackend->searchPrincipals('principals/users', [
  318. '{http://sabredav.org/ns}email-address' => 'foo'
  319. ]);
  320. }
  321. public function testFindByUriByEmail() {
  322. $user = $this->createMock(IUser::class);
  323. $this->userSession->expects($this->once())
  324. ->method('getUser')
  325. ->with()
  326. ->willReturn($user);
  327. $this->groupManager->expects($this->once())
  328. ->method('getUserGroupIds')
  329. ->with($user)
  330. ->willReturn(['group1', 'group2']);
  331. $actual = $this->principalBackend->findByUri('mailto:res1@foo.bar', $this->principalPrefix);
  332. $this->assertEquals($this->principalPrefix . '/backend1-res1', $actual);
  333. }
  334. public function testFindByUriByEmailForbiddenResource() {
  335. $user = $this->createMock(IUser::class);
  336. $this->userSession->expects($this->once())
  337. ->method('getUser')
  338. ->with()
  339. ->willReturn($user);
  340. $this->groupManager->expects($this->once())
  341. ->method('getUserGroupIds')
  342. ->with($user)
  343. ->willReturn(['group1', 'group2']);
  344. $actual = $this->principalBackend->findByUri('mailto:res5@foo.bar', $this->principalPrefix);
  345. $this->assertEquals(null, $actual);
  346. }
  347. public function testFindByUriByEmailNotFound() {
  348. $user = $this->createMock(IUser::class);
  349. $this->userSession->expects($this->once())
  350. ->method('getUser')
  351. ->with()
  352. ->willReturn($user);
  353. $this->groupManager->expects($this->once())
  354. ->method('getUserGroupIds')
  355. ->with($user)
  356. ->willReturn(['group1', 'group2']);
  357. $actual = $this->principalBackend->findByUri('mailto:res99@foo.bar', $this->principalPrefix);
  358. $this->assertEquals(null, $actual);
  359. }
  360. public function testFindByUriByPrincipal() {
  361. $user = $this->createMock(IUser::class);
  362. $this->userSession->expects($this->once())
  363. ->method('getUser')
  364. ->with()
  365. ->willReturn($user);
  366. $this->groupManager->expects($this->once())
  367. ->method('getUserGroupIds')
  368. ->with($user)
  369. ->willReturn(['group1', 'group2']);
  370. $actual = $this->principalBackend->findByUri('mailto:res6@foo.bar', $this->principalPrefix);
  371. $this->assertEquals($this->principalPrefix . '/backend3-res6', $actual);
  372. }
  373. public function testFindByUriByPrincipalForbiddenResource() {
  374. $user = $this->createMock(IUser::class);
  375. $this->userSession->expects($this->once())
  376. ->method('getUser')
  377. ->with()
  378. ->willReturn($user);
  379. $this->groupManager->expects($this->once())
  380. ->method('getUserGroupIds')
  381. ->with($user)
  382. ->willReturn(['group1', 'group2']);
  383. $actual = $this->principalBackend->findByUri('principal:' . $this->principalPrefix . '/backend3-res5', $this->principalPrefix);
  384. $this->assertEquals(null, $actual);
  385. }
  386. public function testFindByUriByPrincipalNotFound() {
  387. $user = $this->createMock(IUser::class);
  388. $this->userSession->expects($this->once())
  389. ->method('getUser')
  390. ->with()
  391. ->willReturn($user);
  392. $this->groupManager->expects($this->once())
  393. ->method('getUserGroupIds')
  394. ->with($user)
  395. ->willReturn(['group1', 'group2']);
  396. $actual = $this->principalBackend->findByUri('principal:' . $this->principalPrefix . '/db-123', $this->principalPrefix);
  397. $this->assertEquals(null, $actual);
  398. }
  399. public function testFindByUriByUnknownUri() {
  400. $user = $this->createMock(IUser::class);
  401. $this->userSession->expects($this->once())
  402. ->method('getUser')
  403. ->with()
  404. ->willReturn($user);
  405. $this->groupManager->expects($this->once())
  406. ->method('getUserGroupIds')
  407. ->with($user)
  408. ->willReturn(['group1', 'group2']);
  409. $actual = $this->principalBackend->findByUri('foobar:blub', $this->principalPrefix);
  410. $this->assertEquals(null, $actual);
  411. }
  412. protected function createTestDatasetInDb() {
  413. $query = self::$realDatabase->getQueryBuilder();
  414. $query->insert($this->mainDbTable)
  415. ->values([
  416. 'backend_id' => $query->createNamedParameter('backend1'),
  417. 'resource_id' => $query->createNamedParameter('res1'),
  418. 'email' => $query->createNamedParameter('res1@foo.bar'),
  419. 'displayname' => $query->createNamedParameter('Beamer1'),
  420. 'group_restrictions' => $query->createNamedParameter('[]'),
  421. ])
  422. ->execute();
  423. $query->insert($this->mainDbTable)
  424. ->values([
  425. 'backend_id' => $query->createNamedParameter('backend1'),
  426. 'resource_id' => $query->createNamedParameter('res2'),
  427. 'email' => $query->createNamedParameter('res2@foo.bar'),
  428. 'displayname' => $query->createNamedParameter('TV1'),
  429. 'group_restrictions' => $query->createNamedParameter('[]'),
  430. ])
  431. ->execute();
  432. $query->insert($this->mainDbTable)
  433. ->values([
  434. 'backend_id' => $query->createNamedParameter('backend2'),
  435. 'resource_id' => $query->createNamedParameter('res3'),
  436. 'email' => $query->createNamedParameter('res3@foo.bar'),
  437. 'displayname' => $query->createNamedParameter('Beamer2'),
  438. 'group_restrictions' => $query->createNamedParameter('[]'),
  439. ])
  440. ->execute();
  441. $id3 = $query->getLastInsertId();
  442. $query->insert($this->mainDbTable)
  443. ->values([
  444. 'backend_id' => $query->createNamedParameter('backend2'),
  445. 'resource_id' => $query->createNamedParameter('res4'),
  446. 'email' => $query->createNamedParameter('res4@foo.bar'),
  447. 'displayname' => $query->createNamedParameter('TV2'),
  448. 'group_restrictions' => $query->createNamedParameter('[]'),
  449. ])
  450. ->execute();
  451. $id4 = $query->getLastInsertId();
  452. $query->insert($this->mainDbTable)
  453. ->values([
  454. 'backend_id' => $query->createNamedParameter('backend3'),
  455. 'resource_id' => $query->createNamedParameter('res5'),
  456. 'email' => $query->createNamedParameter('res5@foo.bar'),
  457. 'displayname' => $query->createNamedParameter('Beamer3'),
  458. 'group_restrictions' => $query->createNamedParameter('["foo", "bar"]'),
  459. ])
  460. ->execute();
  461. $query->insert($this->mainDbTable)
  462. ->values([
  463. 'backend_id' => $query->createNamedParameter('backend3'),
  464. 'resource_id' => $query->createNamedParameter('res6'),
  465. 'email' => $query->createNamedParameter('res6@foo.bar'),
  466. 'displayname' => $query->createNamedParameter('Pointer'),
  467. 'group_restrictions' => $query->createNamedParameter('["group1", "bar"]'),
  468. ])
  469. ->execute();
  470. $id6 = $query->getLastInsertId();
  471. $query->insert($this->metadataDbTable)
  472. ->values([
  473. $this->foreignKey => $query->createNamedParameter($id3),
  474. 'key' => $query->createNamedParameter('{http://nextcloud.com/ns}foo'),
  475. 'value' => $query->createNamedParameter('value1')
  476. ])
  477. ->execute();
  478. $query->insert($this->metadataDbTable)
  479. ->values([
  480. $this->foreignKey => $query->createNamedParameter($id3),
  481. 'key' => $query->createNamedParameter('{http://nextcloud.com/ns}meta2'),
  482. 'value' => $query->createNamedParameter('value2')
  483. ])
  484. ->execute();
  485. $query->insert($this->metadataDbTable)
  486. ->values([
  487. $this->foreignKey => $query->createNamedParameter($id4),
  488. 'key' => $query->createNamedParameter('{http://nextcloud.com/ns}meta1'),
  489. 'value' => $query->createNamedParameter('value1')
  490. ])
  491. ->execute();
  492. $query->insert($this->metadataDbTable)
  493. ->values([
  494. $this->foreignKey => $query->createNamedParameter($id4),
  495. 'key' => $query->createNamedParameter('{http://nextcloud.com/ns}meta3'),
  496. 'value' => $query->createNamedParameter('value3-old')
  497. ])
  498. ->execute();
  499. $query->insert($this->metadataDbTable)
  500. ->values([
  501. $this->foreignKey => $query->createNamedParameter($id6),
  502. 'key' => $query->createNamedParameter('{http://nextcloud.com/ns}meta99'),
  503. 'value' => $query->createNamedParameter('value99')
  504. ])
  505. ->execute();
  506. }
  507. }