From 6cdd9ea9e65d5893341501fb1d2f53a2284b26f2 Mon Sep 17 00:00:00 2001 From: Wogan May Date: Sun, 16 Jul 2023 09:19:38 +0200 Subject: [PATCH 1/2] Fixing export method on DataSet API --- README.md | 24 ++++++++++++------------ src/Connector.php | 4 ++-- src/Service/DataSet.php | 16 +++++----------- tests/DataSetServiceTest.php | 35 +++++++++++++++++++++++++++-------- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 565c999..adf1736 100644 --- a/README.md +++ b/README.md @@ -38,18 +38,18 @@ the objects, and the way you call the methods will work differently. The purpose of this library is to maintain parity with the documented APIs on Domo's Developer site. All client code is being re-implemented from the ground up. The roadmap is currently as follows: -| Capability | Targeted Version | Status | Notes | -|------------------------|------------------|:----------------------:|------------------------------------------| -| Activity Log API | v0.3.0 | 1/1 methods (100%) ✅ | | -| User API | v0.3.0 | 5/5 methods (100%) ✅ | | -| DataSet API | v0.3.0 | 8/13 methods (61%) ⌛ | The "export" method is not supported yet | -| Simple API | v0.4.0 | 0/2 methods (0%) ⏸️ | | -| Stream API | v0.4.0 | 0/12 methods (0%) ⏸️ | | -| Account API | v0.5.0 | 0/8 methods (0%) ⏸️ | | -| Group API | v0.5.0 | 0/8 methods (0%) ⏸️ | | -| Page API | v0.6.0 | 0/9 methods (0%) ⏸️ | | -| Embed Token API | v0.6.0 | 0/2 methods (0%) ⏸️ | | -| Projects and Tasks API | v0.7.0 | 0/21 methods (0%) ⏸️ | | +| Capability | Targeted Version | Status | +|------------------------|------------------|---------| +| Activity Log API | v0.3.0 | 1/1 ✅ | +| User API | v0.3.0 | 5/5 ✅ | +| DataSet API | v0.3.0 | 8/13 ⌛ | +| Simple API | v0.4.0 | 0/2 ⏸️ | +| Stream API | v0.4.0 | 0/12 ⏸️ | +| Account API | v0.5.0 | 0/8 ⏸️ | +| Group API | v0.5.0 | 0/8 ⏸️ | +| Page API | v0.6.0 | 0/9 ⏸️ | +| Embed Token API | v0.6.0 | 0/2 ⏸️ | +| Projects and Tasks API | v0.7.0 | 0/21 ⏸️ | Domo Documentation URL: https://developer.domo.com/portal/8ba9aedad3679-ap-is diff --git a/src/Connector.php b/src/Connector.php index d3bb0fe..d980ba2 100644 --- a/src/Connector.php +++ b/src/Connector.php @@ -179,8 +179,8 @@ public function getCSV(string $url, array $params = []) : string $request = [ 'headers' => [ 'Authorization' => 'Bearer '.$this->getToken(), - 'Content-Type' => 'text/csv', - 'Accept' => 'application/json' + 'Content-Type' => 'application/json', + 'Accept' => 'text/csv' ] ]; diff --git a/src/Service/DataSet.php b/src/Service/DataSet.php index 51fb1d5..2bfcb16 100644 --- a/src/Service/DataSet.php +++ b/src/Service/DataSet.php @@ -89,18 +89,12 @@ public function import(string $id, string $csv) : mixed return $this->client->connector()->putCSV("/v1/datasets/{$id}/data", $csv); } - public function export(string $id, bool $includeHeader = true, string $fileName = "export.csv") : string + public function export(string $id, bool $includeHeader = true) : string { - // As of 9 July 2023, this method doesn't actually work on Domo's API. The below code is how it would normally - // be called, but until the upstream issue is resolved, this method will only return a blank string. - // Q&A URL: https://community-forums.domo.com/main/discussion/59853/does-the-apis-dataset-export-method-work/p1 - throw new DomoPHPException("DataSet@export"); - - // Actual implementation: - // return $this->client->connector()->getCSV("/v1/datasets/{$id}/data", Util::trimArrayKeys([ - // 'includeHeader' => $includeHeader, - // 'fileName' => $fileName - // ])); + return $this->client->connector()->getCSV("/v1/datasets/{$id}/data", Util::trimArrayKeys([ + 'includeHeader' => $includeHeader, + 'fileName' => "export.csv" + ])); } public function getPDP() diff --git a/tests/DataSetServiceTest.php b/tests/DataSetServiceTest.php index 8750f6b..422eea5 100644 --- a/tests/DataSetServiceTest.php +++ b/tests/DataSetServiceTest.php @@ -151,33 +151,52 @@ public function testQueryDataset() public function testExportDataset() { - // As of 9 July 2023, this method returns a `406 Not Acceptable` response regardless of how it is queried. - // Q&A URL: https://community-forums.domo.com/main/discussion/59853/does-the-apis-dataset-export-method-work/p1 - $this->markTestSkipped("API method not supported by Domo.com"); + $client = new Client(); + + $hash = uniqid(); + + $csv = "Field\nRow 1\nRow 2\nRow 3"; + + // Create a new dataset, so we have a target for exporting + $dataset = $client->dataSet()->create("Test ExportDataset {$hash}", [ 'Field' => 'STRING' ]); + $client->dataSet()->import($dataset->id, $csv); + + // Give Domo a chance to run whatever internal processes are required + sleep(10); + + // We should now be able to export this + $exportResult = $client->dataSet()->export($dataset->id); + + // Domo adds a trailing newline to exported data, so comparing the + // trim() value on both sides should work. In addition, this also + // validates that the header is present in the downloaded file. + $this->assertEquals(trim($csv), trim($exportResult)); + } - public function testGetDatasetPDP() + public function testListDatasetPDP() { $this->markTestSkipped("Test not implemented yet"); } - public function testUpdateDatasetPDP() + public function testCreateDatasetPDP() { $this->markTestSkipped("Test not implemented yet"); } - public function testDeleteDatasetPDP() + public function testGetDatasetPDP() { $this->markTestSkipped("Test not implemented yet"); } - public function testListDatasetPDP() + public function testUpdateDatasetPDP() { $this->markTestSkipped("Test not implemented yet"); } - public function testCreateDatasetPDP() + public function testDeleteDatasetPDP() { $this->markTestSkipped("Test not implemented yet"); } + } \ No newline at end of file From 1aa67dc2c30977f3465367b5f00afee107eb7d7a Mon Sep 17 00:00:00 2001 From: Wogan May Date: Sun, 16 Jul 2023 10:11:52 +0200 Subject: [PATCH 2/2] Adding PDP methods to DataSet API --- README.md | 2 +- src/Service/DataSet.php | 67 +++++++++++++--- tests/DataSetServiceTest.php | 149 +++++++++++++++++++++++++++++++++-- 3 files changed, 202 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index adf1736..388a43e 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ being re-implemented from the ground up. The roadmap is currently as follows: |------------------------|------------------|---------| | Activity Log API | v0.3.0 | 1/1 ✅ | | User API | v0.3.0 | 5/5 ✅ | -| DataSet API | v0.3.0 | 8/13 ⌛ | +| DataSet API | v0.3.0 | 13/13 ✅ | | Simple API | v0.4.0 | 0/2 ⏸️ | | Stream API | v0.4.0 | 0/12 ⏸️ | | Account API | v0.5.0 | 0/8 ⏸️ | diff --git a/src/Service/DataSet.php b/src/Service/DataSet.php index 2bfcb16..a7c5fa2 100644 --- a/src/Service/DataSet.php +++ b/src/Service/DataSet.php @@ -97,29 +97,76 @@ public function export(string $id, bool $includeHeader = true) : string ])); } - public function getPDP() + public function listPDP(string $id) : array { - throw new \Exception("Not implemented yet"); + try { + return $this->client->connector()->getJSON("/v1/datasets/{$id}/policies"); + } + catch(ClientException $clientException) + { + throw new DomoPHPException("DataSet@listPDP", $clientException); + } } - public function updatePDP() + /** + * @param string $id The ID of the DataSet to create the PDP on + * @param string $name The user-friendly name of the PDP + * @param array $filters An array of filter criteria to apply to the PDP + * @param array $users An array of user IDs (integer) to link to the PDP + * @param array $groups An array of group IDs (integer) to link to the PDP + * @param string $type The type of PDP, defaults to "user" + * @return mixed The created PDP + * @throws DomoPHPException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function createPDP(string $id, string $name, array $filters = [], array $users = [], array $groups = [], string $type = "user") : mixed { - throw new \Exception("Not implemented yet"); + try { + return $this->client->connector()->postJSON("/v1/datasets/{$id}/policies", [ + 'name' => $name, + 'filters' => $filters, + 'users' => $users, + 'groups' => $groups, + 'type' => $type + ]); + } + catch(ClientException $clientException) + { + throw new DomoPHPException("DataSet@createPDP", $clientException); + } } - public function deletePDP() + public function getPDP(string $id, int $pdp_id) : mixed { - throw new \Exception("Not implemented yet"); + try { + return $this->client->connector()->getJSON("/v1/datasets/{$id}/policies/{$pdp_id}"); + } + catch(ClientException $clientException) + { + throw new DomoPHPException("DataSet@getPDP", $clientException); + } } - public function listPDP() + public function updatePDP(string $id, int $pdp_id, array $updates = []) : mixed { - throw new \Exception("Not implemented yet"); + try { + return $this->client->connector()->putJSON("/v1/datasets/{$id}/policies/{$pdp_id}", $updates); + } + catch(ClientException $clientException) + { + throw new DomoPHPException("DataSet@updatePDP", $clientException); + } } - public function createPDP() + public function deletePDP(string $id, int $pdp_id) : bool { - throw new \Exception("Not implemented yet"); + try { + return $this->client->connector()->delete("/v1/datasets/{$id}/policies/{$pdp_id}"); + } + catch(ClientException $clientException) + { + throw new DomoPHPException("DataSet@deletePDP", $clientException); + } } } \ No newline at end of file diff --git a/tests/DataSetServiceTest.php b/tests/DataSetServiceTest.php index 422eea5..dbf091f 100644 --- a/tests/DataSetServiceTest.php +++ b/tests/DataSetServiceTest.php @@ -176,27 +176,166 @@ public function testExportDataset() public function testListDatasetPDP() { - $this->markTestSkipped("Test not implemented yet"); + $client = new Client(); + + $hash = uniqid(); + + // Create a new dataset, so we have a target for listing the PDP + $dataset = $client->dataSet()->create("Test ListDatasetPDP {$hash}", [ 'Field' => 'STRING' ]); + + // Should now be able to get the PDP on it (an empty array) + $pdp = $client->dataSet()->listPDP($dataset->id); + + // A new dataset should have 1x PDP on it, a default of "All Rows" that has no filters or users + // attached to it. + $this->assertIsArray($pdp); + $this->assertEquals("All Rows", $pdp[0]->name); + $this->assertEmpty($pdp[0]->filters); + $this->assertEmpty($pdp[0]->users); + } public function testCreateDatasetPDP() { - $this->markTestSkipped("Test not implemented yet"); + $client = new Client(); + + $hash = uniqid(); + + // Create a new dataset, so we have a target for creating the PDP + $dataset = $client->dataSet()->create("Test CreateDatasetPDP {$hash}", [ 'Field' => 'STRING' ]); + + // The PDP system adds filters to fields, but Domo doesn't seem to understand that fields are present + // if the dataset is not populated, so let's add some data to it. + $client->dataSet()->import($dataset->id, "Field\nRow 1\nRow 2\nRow 3"); + + // Give Domo a chance to run whatever internal processes are required + sleep(10); + + // Now, attach a PDP to the first available user + $firstUser = $client->user()->list(1); + + $this->assertEquals(865213262, $firstUser[0]->id); + + $users = [ $firstUser[0]->id ]; + + // Allow the user to only see data where 'Field' = 'Row 1' + $filters = [[ + 'column' => 'Field', + 'operator' => 'EQUALS', + 'values' => [ + 'Row 1' + ] + ]]; + + $newPDP = $client->dataSet()->createPDP($dataset->id, "Test PDP #1 - {$hash}", $filters, $users); + + // If we have a PDP object with at least 1 user in it, we're good + $this->assertEquals("Test PDP #1 - {$hash}", $newPDP->name); + $this->assertNotEmpty($newPDP->users); + } public function testGetDatasetPDP() { - $this->markTestSkipped("Test not implemented yet"); + + $client = new Client(); + + $hash = uniqid(); + + // Create a new dataset, so we have a target for getting the PDP + $dataset = $client->dataSet()->create("Test GetDatasetPDP {$hash}", [ 'Field' => 'STRING' ]); + $client->dataSet()->import($dataset->id, "Field\nRow 1\nRow 2\nRow 3"); + + // Give Domo a chance to run whatever internal processes are required + sleep(10); + + // Now, attach a PDP to the first available user + $firstUser = $client->user()->list(1); + $filters = [['column' => 'Field', 'operator' => 'EQUALS', 'values' => [ 'Row 1' ] ]]; + $newPDP = $client->dataSet()->createPDP($dataset->id, "Test PDP #1 - {$hash}", $filters, [ $firstUser[0]->id ]); + + // Now try the GET endpoint and ensure we get the same value back + $retrievedPDP = $client->dataSet()->getPDP($dataset->id, $newPDP->id); + + $this->assertEquals($newPDP->id, $retrievedPDP->id); + } public function testUpdateDatasetPDP() { - $this->markTestSkipped("Test not implemented yet"); + $client = new Client(); + + $hash = uniqid(); + + // Create a new dataset, so we have a target for getting the PDP + $dataset = $client->dataSet()->create("Test UpdateDatasetPDP {$hash}", [ 'Field' => 'STRING' ]); + $client->dataSet()->import($dataset->id, "Field\nRow 1\nRow 2\nRow 3"); + + // Give Domo a chance to run whatever internal processes are required + sleep(10); + + // Now, attach a PDP to the first available user + $firstUser = $client->user()->list(1); + $secondUser = $client->user()->list(1, 1); + $filters = [['column' => 'Field', 'operator' => 'EQUALS', 'values' => [ 'Row 1' ] ]]; + $newPDP = $client->dataSet()->createPDP($dataset->id, "Test PDP #1 - {$hash}", $filters, [ $firstUser[0]->id ]); + + // Update the existing PDP to modify everything about it: + $updates = [ + + // Rename the PDP + 'name' => "Test PDP #1-renamed - {$hash}", + + // Change the only filter on it to check for Field=Row 2 instead + 'filters' => [['column' => 'Field', 'operator' => 'EQUALS', 'values' => [ 'Row 2' ] ]], + + // Update the user to someone totally different + 'users' => [ $secondUser[0]->id ] + + ]; + + // Do the actual update + $client->dataSet()->updatePDP($dataset->id, $newPDP->id, $updates); + + // Retrieve the PDP from scratch for comparison + $retrievedPDP = $client->dataSet()->getPDP($dataset->id, $newPDP->id); + + // Ensure the PDP has updated + $this->assertEquals("Test PDP #1-renamed - {$hash}", $retrievedPDP->name); + $this->assertEquals("Row 2", $retrievedPDP->filters[0]->values[0]); + $this->assertEquals($secondUser[0]->id, $retrievedPDP->users[0]); + } public function testDeleteDatasetPDP() { - $this->markTestSkipped("Test not implemented yet"); + $client = new Client(); + + $hash = uniqid(); + + // Create a new dataset, so we have a target for getting the PDP + $dataset = $client->dataSet()->create("Test DeleteDatasetPDP {$hash}", [ 'Field' => 'STRING' ]); + $client->dataSet()->import($dataset->id, "Field\nRow 1\nRow 2\nRow 3"); + + // Give Domo a chance to run whatever internal processes are required + sleep(10); + + // Now, attach a PDP to the first available user + $firstUser = $client->user()->list(1); + $filters = [['column' => 'Field', 'operator' => 'EQUALS', 'values' => [ 'Row 1' ] ]]; + $newPDP = $client->dataSet()->createPDP($dataset->id, "Test PDP #1 - {$hash}", $filters, [ $firstUser[0]->id ]); + + // Verify it's been created by listing out the policies on the DataSet - there should be 2: + $pdpCheck1 = $client->dataSet()->listPDP($dataset->id); + $this->assertEquals(2, count($pdpCheck1)); + + // Now let's delete ours + $client->dataSet()->deletePDP($dataset->id, $newPDP->id); + + // And confirm it's gone, by re-listing and only seeing 1 PDP on the dataset + $pdpCheck2 = $client->dataSet()->listPDP($dataset->id); + $this->assertEquals(1, count($pdpCheck2)); + } } \ No newline at end of file