From 61d406933e7311a3eb3c0379f1dea8b790459722 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 6 May 2017 19:39:39 +0200 Subject: API: Get History endpoint See http://shaarli.github.io/api-documentation/#links-history-get --- application/api/controllers/History.php | 71 ++++++++++ index.php | 1 + tests/api/controllers/HistoryTest.php | 221 ++++++++++++++++++++++++++++++++ tests/utils/ReferenceHistory.php | 82 ++++++++++++ 4 files changed, 375 insertions(+) create mode 100644 application/api/controllers/History.php create mode 100644 tests/api/controllers/HistoryTest.php create mode 100644 tests/utils/ReferenceHistory.php diff --git a/application/api/controllers/History.php b/application/api/controllers/History.php new file mode 100644 index 00000000..c4ff3e5d --- /dev/null +++ b/application/api/controllers/History.php @@ -0,0 +1,71 @@ +conf->get('resource.history')))->getHistory(); + $history = array_reverse($history); + + // Return history operations from the {offset}th, starting from {since}. + $since = \DateTime::createFromFormat(\DateTime::ATOM, $request->getParam('since')); + $offset = $request->getParam('offset'); + if (empty($offset)) { + $offset = 0; + } + else if (ctype_digit($offset)) { + $offset = (int) $offset; + } else { + throw new ApiBadParametersException('Invalid offset'); + } + + // limit parameter is either a number of links or 'all' for everything. + $limit = $request->getParam('limit'); + if (empty($limit)) { + $limit = count($history); + } else if (ctype_digit($limit)) { + $limit = (int) $limit; + } else { + throw new ApiBadParametersException('Invalid limit'); + } + + $out = []; + $i = 0; + foreach ($history as $entry) { + if ((! empty($since) && $entry['datetime'] <= $since) || count($out) >= $limit) { + break; + } + if (++$i > $offset) { + $out[$i] = $entry; + $out[$i]['datetime'] = $out[$i]['datetime']->format(\DateTime::ATOM); + } + } + $out = array_values($out); + + return $response->withJson($out, 200, $this->jsonStyle); + } +} diff --git a/index.php b/index.php index 02fe2577..cddc9eeb 100644 --- a/index.php +++ b/index.php @@ -2253,6 +2253,7 @@ $app->group('/api/v1', function() { $this->post('/links', '\Shaarli\Api\Controllers\Links:postLink')->setName('postLink'); $this->put('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:putLink')->setName('putLink'); $this->delete('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:deleteLink')->setName('deleteLink'); + $this->get('/history', '\Shaarli\Api\Controllers\History:getHistory')->setName('getHistory'); })->add('\Shaarli\Api\ApiMiddleware'); $response = $app->run(true); diff --git a/tests/api/controllers/HistoryTest.php b/tests/api/controllers/HistoryTest.php new file mode 100644 index 00000000..21e9c0ba --- /dev/null +++ b/tests/api/controllers/HistoryTest.php @@ -0,0 +1,221 @@ +conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->refHistory = new \ReferenceHistory(); + $this->refHistory->write(self::$testHistory); + $this->conf->set('resource.history', self::$testHistory); + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = true; + + $this->controller = new History($this->container); + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testHistory); + } + + /** + * Test /history service without parameter. + */ + public function testGetHistory() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals($this->refHistory->count(), count($data)); + + $this->assertEquals(\History::DELETED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(124, $data[0]['id']); + + $this->assertEquals(\History::SETTINGS, $data[1]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM), + $data[1]['datetime'] + ); + $this->assertNull($data[1]['id']); + + $this->assertEquals(\History::UPDATED, $data[2]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170301_121214')->format(\DateTime::ATOM), + $data[2]['datetime'] + ); + $this->assertEquals(123, $data[2]['id']); + + $this->assertEquals(\History::CREATED, $data[3]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170201_121214')->format(\DateTime::ATOM), + $data[3]['datetime'] + ); + $this->assertEquals(124, $data[3]['id']); + + $this->assertEquals(\History::CREATED, $data[4]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM), + $data[4]['datetime'] + ); + $this->assertEquals(123, $data[4]['id']); + } + + /** + * Test /history service with limit parameter. + */ + public function testGetHistoryLimit() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'limit=1' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::DELETED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(124, $data[0]['id']); + } + + /** + * Test /history service with offset parameter. + */ + public function testGetHistoryOffset() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'offset=4' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::CREATED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(123, $data[0]['id']); + } + + /** + * Test /history service with since parameter. + */ + public function testGetHistorySince() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'since=2017-03-03T00:00:00%2B00:00' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::DELETED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(124, $data[0]['id']); + } + + /** + * Test /history service with since parameter. + */ + public function testGetHistorySinceOffsetLimit() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'since=2017-02-01T00:00:00%2B00:00&offset=1&limit=1' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::SETTINGS, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + } +} diff --git a/tests/utils/ReferenceHistory.php b/tests/utils/ReferenceHistory.php new file mode 100644 index 00000000..20284770 --- /dev/null +++ b/tests/utils/ReferenceHistory.php @@ -0,0 +1,82 @@ +addEntry( + History::CREATED, + DateTime::createFromFormat('Ymd_His', '20170101_121212'), + 123 + ); + + $this->addEntry( + History::CREATED, + DateTime::createFromFormat('Ymd_His', '20170201_121214'), + 124 + ); + + $this->addEntry( + History::UPDATED, + DateTime::createFromFormat('Ymd_His', '20170301_121214'), + 123 + ); + + $this->addEntry( + History::SETTINGS, + DateTime::createFromFormat('Ymd_His', '20170302_121215') + ); + + $this->addEntry( + History::DELETED, + DateTime::createFromFormat('Ymd_His', '20170303_121216'), + 124 + ); + } + + /** + * Adds a new history entry + * + * @param string $event Event identifier + * @param DateTime $datetime creation date + * @param int $id optional: related link ID + */ + protected function addEntry($event, $datetime, $id = null) + { + $link = [ + 'event' => $event, + 'datetime' => $datetime, + 'id' => $id, + ]; + $this->history[] = $link; + $this->count++; + } + + /** + * Writes data to the datastore + * + * @param string $filename write history content to. + */ + public function write($filename) + { + FileUtils::writeFlatDB($filename, $this->history); + } + + /** + * Returns the number of links in the reference data + */ + public function count() + { + return $this->count; + } +} -- cgit v1.2.3