Merge pull request #45532 from nextcloud/feat/publish-resources-room-update
feat: implement public OCP api to update resources and roomspull/43429/head
commit
6121325310
@ -0,0 +1,413 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OC\Calendar; |
||||
|
||||
use OCA\DAV\CalDAV\CalDavBackend; |
||||
use OCP\Calendar\BackendTemporarilyUnavailableException; |
||||
use OCP\Calendar\IMetadataProvider; |
||||
use OCP\Calendar\Resource\IBackend as IResourceBackend; |
||||
use OCP\Calendar\Resource\IManager as IResourceManager; |
||||
use OCP\Calendar\Resource\IResource; |
||||
use OCP\Calendar\Room\IManager as IRoomManager; |
||||
use OCP\Calendar\Room\IRoom; |
||||
use OCP\IDBConnection; |
||||
use Psr\Container\ContainerInterface; |
||||
|
||||
class ResourcesRoomsUpdater { |
||||
public function __construct( |
||||
private ContainerInterface $container, |
||||
private IDBConnection $dbConnection, |
||||
private CalDavBackend $calDavBackend, |
||||
) { |
||||
} |
||||
|
||||
/** |
||||
* Update resource cache from backends |
||||
*/ |
||||
public function updateResources(): void { |
||||
$this->updateFromBackend( |
||||
$this->container->get(IResourceManager::class), |
||||
'calendar_resources', |
||||
'calendar_resources_md', |
||||
'resource_id', |
||||
'principals/calendar-resources' |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Update room cache from backends |
||||
*/ |
||||
public function updateRooms(): void { |
||||
$this->updateFromBackend( |
||||
$this->container->get(IRoomManager::class), |
||||
'calendar_rooms', |
||||
'calendar_rooms_md', |
||||
'room_id', |
||||
'principals/calendar-rooms' |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Update cache from one specific backend manager, either ResourceManager or RoomManager |
||||
* |
||||
* @param IResourceManager|IRoomManager $backendManager |
||||
*/ |
||||
private function updateFromBackend($backendManager, |
||||
string $dbTable, |
||||
string $dbTableMetadata, |
||||
string $foreignKey, |
||||
string $principalPrefix): void { |
||||
$backends = $backendManager->getBackends(); |
||||
|
||||
foreach ($backends as $backend) { |
||||
$backendId = $backend->getBackendIdentifier(); |
||||
|
||||
try { |
||||
if ($backend instanceof IResourceBackend) { |
||||
$list = $backend->listAllResources(); |
||||
} else { |
||||
$list = $backend->listAllRooms(); |
||||
} |
||||
} catch (BackendTemporarilyUnavailableException $ex) { |
||||
continue; |
||||
} |
||||
|
||||
$cachedList = $this->getAllCachedByBackend($dbTable, $backendId); |
||||
$newIds = array_diff($list, $cachedList); |
||||
$deletedIds = array_diff($cachedList, $list); |
||||
$editedIds = array_intersect($list, $cachedList); |
||||
|
||||
foreach ($newIds as $newId) { |
||||
try { |
||||
if ($backend instanceof IResourceBackend) { |
||||
$resource = $backend->getResource($newId); |
||||
} else { |
||||
$resource = $backend->getRoom($newId); |
||||
} |
||||
|
||||
$metadata = []; |
||||
if ($resource instanceof IMetadataProvider) { |
||||
$metadata = $this->getAllMetadataOfBackend($resource); |
||||
} |
||||
} catch (BackendTemporarilyUnavailableException $ex) { |
||||
continue; |
||||
} |
||||
|
||||
$id = $this->addToCache($dbTable, $backendId, $resource); |
||||
$this->addMetadataToCache($dbTableMetadata, $foreignKey, $id, $metadata); |
||||
// we don't create the calendar here, it is created lazily |
||||
// when an event is actually scheduled with this resource / room |
||||
} |
||||
|
||||
foreach ($deletedIds as $deletedId) { |
||||
$id = $this->getIdForBackendAndResource($dbTable, $backendId, $deletedId); |
||||
$this->deleteFromCache($dbTable, $id); |
||||
$this->deleteMetadataFromCache($dbTableMetadata, $foreignKey, $id); |
||||
|
||||
$principalName = implode('-', [$backendId, $deletedId]); |
||||
$this->deleteCalendarDataForResource($principalPrefix, $principalName); |
||||
} |
||||
|
||||
foreach ($editedIds as $editedId) { |
||||
$id = $this->getIdForBackendAndResource($dbTable, $backendId, $editedId); |
||||
|
||||
try { |
||||
if ($backend instanceof IResourceBackend) { |
||||
$resource = $backend->getResource($editedId); |
||||
} else { |
||||
$resource = $backend->getRoom($editedId); |
||||
} |
||||
|
||||
$metadata = []; |
||||
if ($resource instanceof IMetadataProvider) { |
||||
$metadata = $this->getAllMetadataOfBackend($resource); |
||||
} |
||||
} catch (BackendTemporarilyUnavailableException $ex) { |
||||
continue; |
||||
} |
||||
|
||||
$this->updateCache($dbTable, $id, $resource); |
||||
|
||||
if ($resource instanceof IMetadataProvider) { |
||||
$cachedMetadata = $this->getAllMetadataOfCache($dbTableMetadata, $foreignKey, $id); |
||||
$this->updateMetadataCache($dbTableMetadata, $foreignKey, $id, $metadata, $cachedMetadata); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* add entry to cache that exists remotely but not yet in cache |
||||
* |
||||
* @param string $table |
||||
* @param string $backendId |
||||
* @param IResource|IRoom $remote |
||||
* |
||||
* @return int Insert id |
||||
*/ |
||||
private function addToCache(string $table, |
||||
string $backendId, |
||||
$remote): int { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->insert($table) |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter($backendId), |
||||
'resource_id' => $query->createNamedParameter($remote->getId()), |
||||
'email' => $query->createNamedParameter($remote->getEMail()), |
||||
'displayname' => $query->createNamedParameter($remote->getDisplayName()), |
||||
'group_restrictions' => $query->createNamedParameter( |
||||
$this->serializeGroupRestrictions( |
||||
$remote->getGroupRestrictions() |
||||
)) |
||||
]) |
||||
->executeStatement(); |
||||
return $query->getLastInsertId(); |
||||
} |
||||
|
||||
/** |
||||
* @param string $table |
||||
* @param string $foreignKey |
||||
* @param int $foreignId |
||||
* @param array $metadata |
||||
*/ |
||||
private function addMetadataToCache(string $table, |
||||
string $foreignKey, |
||||
int $foreignId, |
||||
array $metadata): void { |
||||
foreach ($metadata as $key => $value) { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->insert($table) |
||||
->values([ |
||||
$foreignKey => $query->createNamedParameter($foreignId), |
||||
'key' => $query->createNamedParameter($key), |
||||
'value' => $query->createNamedParameter($value), |
||||
]) |
||||
->executeStatement(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* delete entry from cache that does not exist anymore remotely |
||||
* |
||||
* @param string $table |
||||
* @param int $id |
||||
*/ |
||||
private function deleteFromCache(string $table, |
||||
int $id): void { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->delete($table) |
||||
->where($query->expr()->eq('id', $query->createNamedParameter($id))) |
||||
->executeStatement(); |
||||
} |
||||
|
||||
/** |
||||
* @param string $table |
||||
* @param string $foreignKey |
||||
* @param int $id |
||||
*/ |
||||
private function deleteMetadataFromCache(string $table, |
||||
string $foreignKey, |
||||
int $id): void { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->delete($table) |
||||
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id))) |
||||
->executeStatement(); |
||||
} |
||||
|
||||
/** |
||||
* update an existing entry in cache |
||||
* |
||||
* @param string $table |
||||
* @param int $id |
||||
* @param IResource|IRoom $remote |
||||
*/ |
||||
private function updateCache(string $table, |
||||
int $id, |
||||
$remote): void { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->update($table) |
||||
->set('email', $query->createNamedParameter($remote->getEMail())) |
||||
->set('displayname', $query->createNamedParameter($remote->getDisplayName())) |
||||
->set('group_restrictions', $query->createNamedParameter( |
||||
$this->serializeGroupRestrictions( |
||||
$remote->getGroupRestrictions() |
||||
))) |
||||
->where($query->expr()->eq('id', $query->createNamedParameter($id))) |
||||
->executeStatement(); |
||||
} |
||||
|
||||
/** |
||||
* @param string $dbTable |
||||
* @param string $foreignKey |
||||
* @param int $id |
||||
* @param array $metadata |
||||
* @param array $cachedMetadata |
||||
*/ |
||||
private function updateMetadataCache(string $dbTable, |
||||
string $foreignKey, |
||||
int $id, |
||||
array $metadata, |
||||
array $cachedMetadata): void { |
||||
$newMetadata = array_diff_key($metadata, $cachedMetadata); |
||||
$deletedMetadata = array_diff_key($cachedMetadata, $metadata); |
||||
|
||||
foreach ($newMetadata as $key => $value) { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->insert($dbTable) |
||||
->values([ |
||||
$foreignKey => $query->createNamedParameter($id), |
||||
'key' => $query->createNamedParameter($key), |
||||
'value' => $query->createNamedParameter($value), |
||||
]) |
||||
->executeStatement(); |
||||
} |
||||
|
||||
foreach ($deletedMetadata as $key => $value) { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->delete($dbTable) |
||||
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id))) |
||||
->andWhere($query->expr()->eq('key', $query->createNamedParameter($key))) |
||||
->executeStatement(); |
||||
} |
||||
|
||||
$existingKeys = array_keys(array_intersect_key($metadata, $cachedMetadata)); |
||||
foreach ($existingKeys as $existingKey) { |
||||
if ($metadata[$existingKey] !== $cachedMetadata[$existingKey]) { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->update($dbTable) |
||||
->set('value', $query->createNamedParameter($metadata[$existingKey])) |
||||
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id))) |
||||
->andWhere($query->expr()->eq('key', $query->createNamedParameter($existingKey))) |
||||
->executeStatement(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* serialize array of group restrictions to store them in database |
||||
* |
||||
* @param array $groups |
||||
* |
||||
* @return string |
||||
*/ |
||||
private function serializeGroupRestrictions(array $groups): string { |
||||
return \json_encode($groups, JSON_THROW_ON_ERROR); |
||||
} |
||||
|
||||
/** |
||||
* Gets all metadata of a backend |
||||
* |
||||
* @param IResource|IRoom $resource |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getAllMetadataOfBackend($resource): array { |
||||
if (!($resource instanceof IMetadataProvider)) { |
||||
return []; |
||||
} |
||||
|
||||
$keys = $resource->getAllAvailableMetadataKeys(); |
||||
$metadata = []; |
||||
foreach ($keys as $key) { |
||||
$metadata[$key] = $resource->getMetadataForKey($key); |
||||
} |
||||
|
||||
return $metadata; |
||||
} |
||||
|
||||
/** |
||||
* @param string $table |
||||
* @param string $foreignKey |
||||
* @param int $id |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getAllMetadataOfCache(string $table, |
||||
string $foreignKey, |
||||
int $id): array { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->select(['key', 'value']) |
||||
->from($table) |
||||
->where($query->expr()->eq($foreignKey, $query->createNamedParameter($id))); |
||||
$result = $query->executeQuery(); |
||||
$rows = $result->fetchAll(); |
||||
$result->closeCursor(); |
||||
|
||||
$metadata = []; |
||||
foreach ($rows as $row) { |
||||
$metadata[$row['key']] = $row['value']; |
||||
} |
||||
|
||||
return $metadata; |
||||
} |
||||
|
||||
/** |
||||
* Gets all cached rooms / resources by backend |
||||
* |
||||
* @param $tableName |
||||
* @param $backendId |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getAllCachedByBackend(string $tableName, |
||||
string $backendId): array { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->select('resource_id') |
||||
->from($tableName) |
||||
->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId))); |
||||
$result = $query->executeQuery(); |
||||
$rows = $result->fetchAll(); |
||||
$result->closeCursor(); |
||||
|
||||
return array_map(function ($row): string { |
||||
return $row['resource_id']; |
||||
}, $rows); |
||||
} |
||||
|
||||
/** |
||||
* @param $principalPrefix |
||||
* @param $principalUri |
||||
*/ |
||||
private function deleteCalendarDataForResource(string $principalPrefix, |
||||
string $principalUri): void { |
||||
$calendar = $this->calDavBackend->getCalendarByUri( |
||||
implode('/', [$principalPrefix, $principalUri]), |
||||
CalDavBackend::RESOURCE_BOOKING_CALENDAR_URI); |
||||
|
||||
if ($calendar !== null) { |
||||
$this->calDavBackend->deleteCalendar( |
||||
$calendar['id'], |
||||
true // Because this wasn't deleted by a user |
||||
); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param $table |
||||
* @param $backendId |
||||
* @param $resourceId |
||||
* |
||||
* @return int |
||||
*/ |
||||
private function getIdForBackendAndResource(string $table, |
||||
string $backendId, |
||||
string $resourceId): int { |
||||
$query = $this->dbConnection->getQueryBuilder(); |
||||
$query->select('id') |
||||
->from($table) |
||||
->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId))) |
||||
->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resourceId))); |
||||
$result = $query->executeQuery(); |
||||
|
||||
$id = (int) $result->fetchOne(); |
||||
$result->closeCursor(); |
||||
return $id; |
||||
} |
||||
} |
||||
@ -0,0 +1,439 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace Test\Calendar; |
||||
|
||||
use OC\Calendar\ResourcesRoomsUpdater; |
||||
use OCA\DAV\CalDAV\CalDavBackend; |
||||
use OCP\Calendar\BackendTemporarilyUnavailableException; |
||||
use OCP\Calendar\IMetadataProvider; |
||||
use OCP\Calendar\Resource\IBackend; |
||||
use OCP\Calendar\Resource\IManager as IResourceManager; |
||||
use OCP\Calendar\Resource\IResource; |
||||
use OCP\Calendar\Room\IManager as IRoomManager; |
||||
use PHPUnit\Framework\MockObject\MockObject; |
||||
use Psr\Container\ContainerInterface; |
||||
use Test\TestCase; |
||||
|
||||
interface tmpI extends IResource, IMetadataProvider { |
||||
} |
||||
|
||||
class ResourcesRoomsUpdaterTest extends TestCase { |
||||
private ResourcesRoomsUpdater $updater; |
||||
|
||||
/** @var IResourceManager|MockObject */ |
||||
private $resourceManager; |
||||
|
||||
/** @var IRoomManager|MockObject */ |
||||
private $roomManager; |
||||
|
||||
/** @var ContainerInterface|MockObject */ |
||||
private $container; |
||||
|
||||
/** @var CalDavBackend|MockObject */ |
||||
private $calDavBackend; |
||||
|
||||
protected function setUp(): void { |
||||
parent::setUp(); |
||||
|
||||
$this->resourceManager = $this->createMock(IResourceManager::class); |
||||
$this->roomManager = $this->createMock(IRoomManager::class); |
||||
$this->container = $this->createMock(ContainerInterface::class); |
||||
$this->calDavBackend = $this->createMock(CalDavBackend::class); |
||||
|
||||
$this->container->method('get') |
||||
->willReturnMap([ |
||||
[IResourceManager::class, $this->resourceManager], |
||||
[IRoomManager::class, $this->roomManager], |
||||
]); |
||||
|
||||
$this->updater = new ResourcesRoomsUpdater( |
||||
$this->container, |
||||
self::$realDatabase, |
||||
$this->calDavBackend |
||||
); |
||||
} |
||||
|
||||
protected function tearDown(): void { |
||||
$query = self::$realDatabase->getQueryBuilder(); |
||||
$query->delete('calendar_resources')->execute(); |
||||
$query->delete('calendar_resources_md')->execute(); |
||||
$query->delete('calendar_rooms')->execute(); |
||||
$query->delete('calendar_rooms_md')->execute(); |
||||
} |
||||
|
||||
/** |
||||
* Data in Cache: |
||||
* resources: |
||||
* [backend1, res1, Beamer1, {}] - [] |
||||
* [backend1, res2, TV1, {}] - [] |
||||
* [backend2, res3, Beamer2, {}] - ['meta1' => 'value1', 'meta2' => 'value2'] |
||||
* [backend2, res4, TV2, {}] - ['meta1' => 'value1', 'meta3' => 'value3-old'] |
||||
* [backend3, res5, Beamer3, {}] - [] |
||||
* [backend3, res6, Pointer, {foo, bar}] - ['meta99' => 'value99'] |
||||
* |
||||
* Data in Backend: |
||||
* backend1 gone |
||||
* backend2 throws BackendTemporarilyUnavailableException |
||||
* [backend3, res6, Pointer123, {foo, biz}] - ['meta99' => 'value99-new', 'meta123' => 'meta456'] |
||||
* [backend3, res7, Resource4, {biz}] - ['meta1' => 'value1'] |
||||
* [backend4, res8, Beamer, {}] - ['meta2' => 'value2'] |
||||
* [backend4, res9, Beamer2, {}] - [] |
||||
* |
||||
* Expected after run: |
||||
* [backend1, res1, Beamer1, {}] - [] |
||||
* [backend1, res2, TV1, {}] - [] |
||||
* [backend2, res3, Beamer2, {}] - ['meta1' => 'value1', 'meta2' => 'value2'] |
||||
* [backend2, res4, TV2, {}] - ['meta1' => 'value1', 'meta3' => 'value3-old'] |
||||
* [backend3, res6, Pointer123, {foo, biz}] - ['meta99' => 'value99-new', 'meta123' => 'meta456'] |
||||
* [backend3, res7, Resource4, {biz}] - ['meta1' => 'value1'] |
||||
* [backend4, res8, Beamer, {}] - ['meta2' => 'value2'] |
||||
* [backend4, res9, Beamer2, {}] - [] |
||||
*/ |
||||
|
||||
public function testUpdateBoth(): void { |
||||
$this->createTestResourcesInCache(); |
||||
|
||||
$backend2 = $this->createMock(IBackend::class); |
||||
$backend3 = $this->createMock(IBackend::class); |
||||
$backend4 = $this->createMock(IBackend::class); |
||||
|
||||
$res6 = $this->createMock(tmpI::class); |
||||
$res7 = $this->createMock(tmpI::class); |
||||
$res8 = $this->createMock(tmpI::class); |
||||
$res9 = $this->createMock(IResource::class); |
||||
|
||||
$backend2->method('getBackendIdentifier') |
||||
->willReturn('backend2'); |
||||
$backend2->method('listAllResources') |
||||
->will($this->throwException(new BackendTemporarilyUnavailableException())); |
||||
$backend2->method('getResource') |
||||
->will($this->throwException(new BackendTemporarilyUnavailableException())); |
||||
$backend2->method('getAllResources') |
||||
->will($this->throwException(new BackendTemporarilyUnavailableException())); |
||||
$backend3->method('getBackendIdentifier') |
||||
->willReturn('backend3'); |
||||
$backend3->method('listAllResources') |
||||
->willReturn(['res6', 'res7']); |
||||
$backend3->method('getResource') |
||||
->willReturnMap([ |
||||
['res6', $res6], |
||||
['res7', $res7], |
||||
]); |
||||
$backend4->method('getBackendIdentifier') |
||||
->willReturn('backend4'); |
||||
$backend4->method('listAllResources') |
||||
->willReturn(['res8', 'res9']); |
||||
$backend4->method('getResource') |
||||
->willReturnMap([ |
||||
['res8', $res8], |
||||
['res9', $res9], |
||||
]); |
||||
|
||||
$res6->method('getId')->willReturn('res6'); |
||||
$res6->method('getDisplayName')->willReturn('Pointer123'); |
||||
$res6->method('getGroupRestrictions')->willReturn(['foo', 'biz']); |
||||
$res6->method('getEMail')->willReturn('res6@foo.bar'); |
||||
$res6->method('getBackend')->willReturn($backend3); |
||||
|
||||
$res6->method('getAllAvailableMetadataKeys')->willReturn(['meta99', 'meta123']); |
||||
$res6->method('getMetadataForKey')->willReturnCallback(function ($key) { |
||||
switch ($key) { |
||||
case 'meta99': |
||||
return 'value99-new'; |
||||
|
||||
case 'meta123': |
||||
return 'meta456'; |
||||
|
||||
default: |
||||
return null; |
||||
} |
||||
}); |
||||
|
||||
$res7->method('getId')->willReturn('res7'); |
||||
$res7->method('getDisplayName')->willReturn('Resource4'); |
||||
$res7->method('getGroupRestrictions')->willReturn(['biz']); |
||||
$res7->method('getEMail')->willReturn('res7@foo.bar'); |
||||
$res7->method('getBackend')->willReturn($backend3); |
||||
$res7->method('getAllAvailableMetadataKeys')->willReturn(['meta1']); |
||||
$res7->method('getMetadataForKey')->willReturnCallback(function ($key) { |
||||
switch ($key) { |
||||
case 'meta1': |
||||
return 'value1'; |
||||
|
||||
default: |
||||
return null; |
||||
} |
||||
}); |
||||
|
||||
$res8->method('getId')->willReturn('res8'); |
||||
$res8->method('getDisplayName')->willReturn('Beamer'); |
||||
$res8->method('getGroupRestrictions')->willReturn([]); |
||||
$res8->method('getEMail')->willReturn('res8@foo.bar'); |
||||
$res8->method('getBackend')->willReturn($backend4); |
||||
$res8->method('getAllAvailableMetadataKeys')->willReturn(['meta2']); |
||||
$res8->method('getMetadataForKey')->willReturnCallback(function ($key) { |
||||
switch ($key) { |
||||
case 'meta2': |
||||
return 'value2'; |
||||
|
||||
default: |
||||
return null; |
||||
} |
||||
}); |
||||
|
||||
$res9->method('getId')->willReturn('res9'); |
||||
$res9->method('getDisplayName')->willReturn('Beamer2'); |
||||
$res9->method('getGroupRestrictions')->willReturn([]); |
||||
$res9->method('getEMail')->willReturn('res9@foo.bar'); |
||||
$res9->method('getBackend')->willReturn($backend4); |
||||
|
||||
$this->resourceManager |
||||
->method('getBackends') |
||||
->willReturn([ |
||||
$backend2, $backend3, $backend4 |
||||
]); |
||||
$this->resourceManager |
||||
->method('getBackend') |
||||
->willReturnMap([ |
||||
['backend2', $backend2], |
||||
['backend3', $backend3], |
||||
['backend4', $backend4], |
||||
]); |
||||
|
||||
$this->updater->updateResources(); |
||||
$this->updater->updateRooms(); |
||||
|
||||
$query = self::$realDatabase->getQueryBuilder(); |
||||
$query->select('*')->from('calendar_resources'); |
||||
|
||||
$rows = []; |
||||
$ids = []; |
||||
$stmt = $query->execute(); |
||||
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
||||
$ids[$row['backend_id'] . '::' . $row['resource_id']] = $row['id']; |
||||
unset($row['id']); |
||||
$rows[] = $row; |
||||
} |
||||
|
||||
$this->assertEquals([ |
||||
[ |
||||
'backend_id' => 'backend1', |
||||
'resource_id' => 'res1', |
||||
'displayname' => 'Beamer1', |
||||
'email' => 'res1@foo.bar', |
||||
'group_restrictions' => '[]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend1', |
||||
'resource_id' => 'res2', |
||||
'displayname' => 'TV1', |
||||
'email' => 'res2@foo.bar', |
||||
'group_restrictions' => '[]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend2', |
||||
'resource_id' => 'res3', |
||||
'displayname' => 'Beamer2', |
||||
'email' => 'res3@foo.bar', |
||||
'group_restrictions' => '[]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend2', |
||||
'resource_id' => 'res4', |
||||
'displayname' => 'TV2', |
||||
'email' => 'res4@foo.bar', |
||||
'group_restrictions' => '[]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend3', |
||||
'resource_id' => 'res6', |
||||
'displayname' => 'Pointer123', |
||||
'email' => 'res6@foo.bar', |
||||
'group_restrictions' => '["foo","biz"]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend3', |
||||
'resource_id' => 'res7', |
||||
'displayname' => 'Resource4', |
||||
'email' => 'res7@foo.bar', |
||||
'group_restrictions' => '["biz"]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend4', |
||||
'resource_id' => 'res8', |
||||
'displayname' => 'Beamer', |
||||
'email' => 'res8@foo.bar', |
||||
'group_restrictions' => '[]', |
||||
], |
||||
[ |
||||
'backend_id' => 'backend4', |
||||
'resource_id' => 'res9', |
||||
'displayname' => 'Beamer2', |
||||
'email' => 'res9@foo.bar', |
||||
'group_restrictions' => '[]', |
||||
], |
||||
], $rows); |
||||
|
||||
$query2 = self::$realDatabase->getQueryBuilder(); |
||||
$query2->select('*')->from('calendar_resources_md'); |
||||
|
||||
$rows2 = []; |
||||
$stmt = $query2->execute(); |
||||
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
||||
unset($row['id']); |
||||
$rows2[] = $row; |
||||
} |
||||
|
||||
$this->assertEquals([ |
||||
[ |
||||
'resource_id' => $ids['backend2::res3'], |
||||
'key' => 'meta1', |
||||
'value' => 'value1', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend2::res3'], |
||||
'key' => 'meta2', |
||||
'value' => 'value2', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend2::res4'], |
||||
'key' => 'meta1', |
||||
'value' => 'value1', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend2::res4'], |
||||
'key' => 'meta3', |
||||
'value' => 'value3-old', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend3::res6'], |
||||
'key' => 'meta99', |
||||
'value' => 'value99-new', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend3::res7'], |
||||
'key' => 'meta1', |
||||
'value' => 'value1', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend3::res6'], |
||||
'key' => 'meta123', |
||||
'value' => 'meta456', |
||||
], |
||||
[ |
||||
'resource_id' => $ids['backend4::res8'], |
||||
'key' => 'meta2', |
||||
'value' => 'value2', |
||||
] |
||||
], $rows2); |
||||
} |
||||
|
||||
protected function createTestResourcesInCache() { |
||||
$query = self::$realDatabase->getQueryBuilder(); |
||||
$query->insert('calendar_resources') |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter('backend1'), |
||||
'resource_id' => $query->createNamedParameter('res1'), |
||||
'email' => $query->createNamedParameter('res1@foo.bar'), |
||||
'displayname' => $query->createNamedParameter('Beamer1'), |
||||
'group_restrictions' => $query->createNamedParameter('[]'), |
||||
]) |
||||
->execute(); |
||||
|
||||
$query->insert('calendar_resources') |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter('backend1'), |
||||
'resource_id' => $query->createNamedParameter('res2'), |
||||
'email' => $query->createNamedParameter('res2@foo.bar'), |
||||
'displayname' => $query->createNamedParameter('TV1'), |
||||
'group_restrictions' => $query->createNamedParameter('[]'), |
||||
]) |
||||
->execute(); |
||||
|
||||
$query->insert('calendar_resources') |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter('backend2'), |
||||
'resource_id' => $query->createNamedParameter('res3'), |
||||
'email' => $query->createNamedParameter('res3@foo.bar'), |
||||
'displayname' => $query->createNamedParameter('Beamer2'), |
||||
'group_restrictions' => $query->createNamedParameter('[]'), |
||||
]) |
||||
->execute(); |
||||
$id3 = $query->getLastInsertId(); |
||||
|
||||
$query->insert('calendar_resources') |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter('backend2'), |
||||
'resource_id' => $query->createNamedParameter('res4'), |
||||
'email' => $query->createNamedParameter('res4@foo.bar'), |
||||
'displayname' => $query->createNamedParameter('TV2'), |
||||
'group_restrictions' => $query->createNamedParameter('[]'), |
||||
]) |
||||
->execute(); |
||||
$id4 = $query->getLastInsertId(); |
||||
|
||||
$query->insert('calendar_resources') |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter('backend3'), |
||||
'resource_id' => $query->createNamedParameter('res5'), |
||||
'email' => $query->createNamedParameter('res5@foo.bar'), |
||||
'displayname' => $query->createNamedParameter('Beamer3'), |
||||
'group_restrictions' => $query->createNamedParameter('[]'), |
||||
]) |
||||
->execute(); |
||||
|
||||
$query->insert('calendar_resources') |
||||
->values([ |
||||
'backend_id' => $query->createNamedParameter('backend3'), |
||||
'resource_id' => $query->createNamedParameter('res6'), |
||||
'email' => $query->createNamedParameter('res6@foo.bar'), |
||||
'displayname' => $query->createNamedParameter('Pointer'), |
||||
'group_restrictions' => $query->createNamedParameter('["foo", "bar"]'), |
||||
]) |
||||
->execute(); |
||||
$id6 = $query->getLastInsertId(); |
||||
|
||||
$query->insert('calendar_resources_md') |
||||
->values([ |
||||
'resource_id' => $query->createNamedParameter($id3), |
||||
'key' => $query->createNamedParameter('meta1'), |
||||
'value' => $query->createNamedParameter('value1') |
||||
]) |
||||
->execute(); |
||||
$query->insert('calendar_resources_md') |
||||
->values([ |
||||
'resource_id' => $query->createNamedParameter($id3), |
||||
'key' => $query->createNamedParameter('meta2'), |
||||
'value' => $query->createNamedParameter('value2') |
||||
]) |
||||
->execute(); |
||||
$query->insert('calendar_resources_md') |
||||
->values([ |
||||
'resource_id' => $query->createNamedParameter($id4), |
||||
'key' => $query->createNamedParameter('meta1'), |
||||
'value' => $query->createNamedParameter('value1') |
||||
]) |
||||
->execute(); |
||||
$query->insert('calendar_resources_md') |
||||
->values([ |
||||
'resource_id' => $query->createNamedParameter($id4), |
||||
'key' => $query->createNamedParameter('meta3'), |
||||
'value' => $query->createNamedParameter('value3-old') |
||||
]) |
||||
->execute(); |
||||
$query->insert('calendar_resources_md') |
||||
->values([ |
||||
'resource_id' => $query->createNamedParameter($id6), |
||||
'key' => $query->createNamedParameter('meta99'), |
||||
'value' => $query->createNamedParameter('value99') |
||||
]) |
||||
->execute(); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue