public function testExportFormatMultiple() { foreach (self::$formats as $format) { $response = API::userGet(self::$config['userID'], "items?format={$format}"); $this->assert200($response); $this->assertContentType(self::$multiResponses[$format]['contentType'], $response); $this->assertEquals(self::$multiResponses[$format]['content'], $response->getBody()); } }
/** * An object type's primary data cache for a library has to be created before * */ public function testCacheCreatorPrimaryData() { $data = array("title" => "Title", "creators" => array(array("creatorType" => "author", "firstName" => "First", "lastName" => "Last"), array("creatorType" => "editor", "firstName" => "Ed", "lastName" => "McEditor"))); $key = API::createItem("book", $data, $this, 'key'); $response = API::userGet(self::$config['userID'], "items/{$key}?content=csljson"); $json = json_decode(API::getContentFromResponse($response)); $this->assertEquals("First", $json->author[0]->given); $this->assertEquals("Last", $json->author[0]->family); $this->assertEquals("Ed", $json->editor[0]->given); $this->assertEquals("McEditor", $json->editor[0]->family); }
public function testCreateItemAndAnonymousRead() { // Create item API::useAPIKey(self::$config['apiKey']); $json = API::getItemTemplate("book"); $response = API::userPost(self::$config['userID'], "publications/items", json_encode([$json])); $this->assert200ForObject($response); // Test notifications (which we do here instead of in NotificationsTest.php because // we want to test library creation above (though we could delete the publications // library explicitly first)) $this->assertCountNotifications(1, $response); $this->assertHasNotification(['event' => 'topicUpdated', 'topic' => '/users/' . self::$config['userID'] . '/publications'], $response); $json = API::getJSONFromResponse($response); $itemKey = $json['success'][0]; // Read item anonymously API::useAPIKey(""); $libraryName = self::$config['username'] . '’s Publications'; // JSON $response = API::userGet(self::$config['userID'], "publications/items/{$itemKey}"); $this->assert200($response); $json = API::getJSONFromResponse($response); $this->assertEquals($libraryName, $json['library']['name']); $this->assertEquals("publications", $json['library']['type']); // Atom $response = API::userGet(self::$config['userID'], "publications/items/{$itemKey}?format=atom"); $this->assert200($response); $xml = API::getXMLFromResponse($response); $this->assertEquals($libraryName, (string) $xml->author->name); }
public function testAuthorization() { $apiKey = self::$config['apiKey']; API::useAPIKey(false); // Zotero-API-Key header $response = API::userGet(self::$config['userID'], "items", ["Zotero-API-Key: {$apiKey}"]); $this->assertHTTPStatus(200, $response); // Authorization header $response = API::userGet(self::$config['userID'], "items", ["Authorization: Bearer {$apiKey}"]); $this->assertHTTPStatus(200, $response); // Query parameter $response = API::userGet(self::$config['userID'], "items?key={$apiKey}"); $this->assertHTTPStatus(200, $response); // Zotero-API-Key header and query parameter $response = API::userGet(self::$config['userID'], "items?key={$apiKey}", ["Zotero-API-Key: {$apiKey}"]); $this->assertHTTPStatus(200, $response); // No key $response = API::userGet(self::$config['userID'], "items"); $this->assertHTTPStatus(403, $response); // Zotero-API-Key header and empty key (which is still an error) $response = API::userGet(self::$config['userID'], "items?key=", ["Zotero-API-Key: {$apiKey}"]); $this->assertHTTPStatus(400, $response); // Zotero-API-Key header and incorrect Authorization key (which is ignored) $response = API::userGet(self::$config['userID'], "items", ["Zotero-API-Key: {$apiKey}", "Authorization: Bearer invalidkey"]); $this->assertHTTPStatus(200, $response); // Zotero-API-Key header and key mismatch $response = API::userGet(self::$config['userID'], "items?key=invalidkey", ["Zotero-API-Key: {$apiKey}"]); $this->assertHTTPStatus(400, $response); // Invalid Bearer format $response = API::userGet(self::$config['userID'], "items", ["Authorization: Bearer key={$apiKey}"]); $this->assertHTTPStatus(400, $response); // Ignored OAuth 1.0 header, with key query parameter $response = API::userGet(self::$config['userID'], "items?key={$apiKey}", ['Authorization: OAuth oauth_consumer_key="aaaaaaaaaaaaaaaaaaaa"']); $this->assertHTTPStatus(200, $response); // Ignored OAuth 1.0 header, with no key query parameter $response = API::userGet(self::$config['userID'], "items", ['Authorization: OAuth oauth_consumer_key="aaaaaaaaaaaaaaaaaaaa"']); $this->assertHTTPStatus(403, $response); }
private function _testSinceContent($param) { API::userClear(self::$config['userID']); // Store content for one item $key = API::createItem("book", false, $this, 'key'); $json = API::createAttachmentItem("imported_url", [], $key, $this, 'jsonData'); $key1 = $json['key']; $content = "Here is some full-text content"; $response = API::userPut(self::$config['userID'], "items/{$key1}/fulltext", json_encode(["content" => $content]), array("Content-Type: application/json")); $this->assert204($response); $contentVersion1 = $response->getHeader("Last-Modified-Version"); $this->assertGreaterThan(0, $contentVersion1); // And another $key = API::createItem("book", false, $this, 'key'); $json = API::createAttachmentItem("imported_url", [], $key, $this, 'jsonData'); $key2 = $json['key']; $response = API::userPut(self::$config['userID'], "items/{$key2}/fulltext", json_encode(["content" => $content]), array("Content-Type: application/json")); $this->assert204($response); $contentVersion2 = $response->getHeader("Last-Modified-Version"); $this->assertGreaterThan(0, $contentVersion2); // Get newer one $response = API::userGet(self::$config['userID'], "fulltext?{$param}={$contentVersion1}"); $this->assert200($response); $this->assertContentType("application/json", $response); $this->assertEquals($contentVersion2, $response->getHeader("Last-Modified-Version")); $json = API::getJSONFromResponse($response); $this->assertCount(1, $json); $this->assertArrayHasKey($key2, $json); $this->assertEquals($contentVersion2, $json[$key2]); // Get both with since=0 $response = API::userGet(self::$config['userID'], "fulltext?{$param}=0"); $this->assert200($response); $this->assertContentType("application/json", $response); $json = API::getJSONFromResponse($response); $this->assertCount(2, $json); $this->assertArrayHasKey($key1, $json); $this->assertEquals($contentVersion1, $json[$key1]); $this->assertArrayHasKey($key1, $json); $this->assertEquals($contentVersion2, $json[$key2]); }
public function testCollectionItems() { $collectionKey = API::createCollection('Test', false, $this, 'key'); $json = API::createItem("book", ['collections' => [$collectionKey]], $this, 'jsonData'); $itemKey1 = $json['key']; $itemVersion1 = $json['version']; $this->assertEquals([$collectionKey], $json['collections']); $json = API::createItem("journalArticle", ['collections' => [$collectionKey]], $this, 'jsonData'); $itemKey2 = $json['key']; $itemVersion2 = $json['version']; $this->assertEquals([$collectionKey], $json['collections']); $childItemKey1 = API::createAttachmentItem("linked_url", [], $itemKey1, $this, 'key'); $childItemKey2 = API::createAttachmentItem("linked_url", [], $itemKey2, $this, 'key'); $response = API::userGet(self::$config['userID'], "collections/{$collectionKey}/items?format=keys"); $this->assert200($response); $keys = explode("\n", trim($response->getBody())); $this->assertCount(4, $keys); $this->assertContains($itemKey1, $keys); $this->assertContains($itemKey2, $keys); $this->assertContains($childItemKey1, $keys); $this->assertContains($childItemKey2, $keys); $response = API::userGet(self::$config['userID'], "collections/{$collectionKey}/items/top?format=keys"); $this->assert200($response); $keys = explode("\n", trim($response->getBody())); $this->assertCount(2, $keys); $this->assertContains($itemKey1, $keys); $this->assertContains($itemKey2, $keys); }
public function testAcceptHeader() { $response = API::userGet(self::$config['userID'], "items", ["Accept: application/atom+xml,application/rdf+xml,application/rss+xml,application/xml,text/xml,*/*"]); $this->assertContentType('application/atom+xml', $response); // But format= should still override $response = API::userGet(self::$config['userID'], "items?format=json", ["Accept: application/atom+xml,application/rdf+xml,application/rss+xml,application/xml,text/xml,*/*"]); $this->assertContentType('application/json', $response); }
public function testUnicodeTitle() { $title = "Tést"; $key = API::createItem("book", array("title" => $title), $this, 'key'); // Test entry (JSON) $response = API::userGet( self::$config['userID'], "items/$key" ); $this->assertContains('"title": "Tést"', $response->getBody()); // Test feed (JSON) $response = API::userGet( self::$config['userID'], "items" ); $this->assertContains('"title": "Tést"', $response->getBody()); // Test entry (Atom) $response = API::userGet( self::$config['userID'], "items/$key?content=json" ); $this->assertContains('"title": "Tést"', $response->getBody()); // Test feed (Atom) $response = API::userGet( self::$config['userID'], "items?content=json" ); $this->assertContains('"title": "Tést"', $response->getBody()); }
public function testAddFileClientZip() { API::userClear(self::$config['userID']); $auth = array('username' => self::$config['username'], 'password' => self::$config['password']); // Get last storage sync $response = API::userGet(self::$config['userID'], "laststoragesync?auth=1", array(), $auth); $this->assert404($response); $json = API::createItem("book", false, $this, 'jsonData'); $key = $json['key']; $fileContentType = "text/html"; $fileCharset = "UTF-8"; $fileFilename = "file.html"; $fileModtime = time(); $json = API::createAttachmentItem("imported_url", [], $key, $this, 'jsonData'); $key = $json['key']; $version = $json['version']; $json['contentType'] = $fileContentType; $json['charset'] = $fileCharset; $json['filename'] = $fileFilename; $response = API::userPut(self::$config['userID'], "items/{$key}", json_encode($json), array("Content-Type: application/json")); $this->assert204($response); // Get a sync timestamp from before the file is updated sleep(1); require_once 'include/sync.inc.php'; $sessionID = Sync::login(); $xml = Sync::updated($sessionID); $lastsync = (int) $xml['timestamp']; Sync::logout($sessionID); // Get file info $response = API::userGet(self::$config['userID'], "items/{$json['key']}/file?auth=1&iskey=1&version=1&info=1", array(), $auth); $this->assert404($response); $zip = new \ZipArchive(); $file = "work/{$key}.zip"; if ($zip->open($file, \ZIPARCHIVE::CREATE) !== TRUE) { throw new Exception("Cannot open ZIP file"); } $zip->addFromString($fileFilename, self::getRandomUnicodeString()); $zip->addFromString("file.css", self::getRandomUnicodeString()); $zip->close(); $hash = md5_file($file); $filename = $key . ".zip"; $size = filesize($file); $fileContents = file_get_contents($file); // Get upload authorization $response = API::userPost(self::$config['userID'], "items/{$json['key']}/file?auth=1&iskey=1&version=1", $this->implodeParams(array("md5" => $hash, "filename" => $filename, "filesize" => $size, "mtime" => $fileModtime, "zip" => 1)), array("Content-Type: application/x-www-form-urlencoded"), $auth); $this->assert200($response); $this->assertContentType("application/xml", $response); $xml = new SimpleXMLElement($response->getBody()); self::$toDelete[] = "{$hash}"; $boundary = "---------------------------" . rand(); $postData = ""; foreach ($xml->params->children() as $key => $val) { $postData .= "--" . $boundary . "\r\nContent-Disposition: form-data; " . "name=\"{$key}\"\r\n\r\n{$val}\r\n"; } $postData .= "--" . $boundary . "\r\nContent-Disposition: form-data; " . "name=\"file\"\r\n\r\n" . $fileContents . "\r\n"; $postData .= "--" . $boundary . "--"; // Upload to S3 $response = HTTP::post((string) $xml->url, $postData, array("Content-Type: multipart/form-data; boundary=" . $boundary)); $this->assert201($response); // // Register upload // $response = API::userPost(self::$config['userID'], "items/{$json['key']}/file?auth=1&iskey=1&version=1", "update=" . $xml->key . "&mtime=" . $fileModtime, array("Content-Type: application/x-www-form-urlencoded"), $auth); $this->assert204($response); // Verify attachment item metadata $response = API::userGet(self::$config['userID'], "items/{$json['key']}"); $json = API::getJSONFromResponse($response)['data']; $this->assertEquals($hash, $json['md5']); $this->assertEquals($fileFilename, $json['filename']); $this->assertEquals($fileModtime, $json['mtime']); // Make sure attachment item wasn't updated (or else the client // will get a conflict when it tries to update the metadata) $sessionID = Sync::login(); $xml = Sync::updated($sessionID, $lastsync); Sync::logout($sessionID); $this->assertEquals(0, $xml->updated[0]->count()); $response = API::userGet(self::$config['userID'], "laststoragesync?auth=1", array(), array('username' => self::$config['username'], 'password' => self::$config['password'])); $this->assert200($response); $mtime = $response->getBody(); $this->assertRegExp('/^[0-9]{10}$/', $mtime); // File exists $response = API::userPost(self::$config['userID'], "items/{$json['key']}/file?auth=1&iskey=1&version=1", $this->implodeParams(array("md5" => $hash, "filename" => $filename, "filesize" => $size, "mtime" => $fileModtime + 1000, "zip" => 1)), array("Content-Type: application/x-www-form-urlencoded"), $auth); $this->assert200($response); $this->assertContentType("application/xml", $response); $this->assertEquals("<exists/>", $response->getBody()); // Make sure attachment item still wasn't updated $sessionID = Sync::login(); $xml = Sync::updated($sessionID, $lastsync); Sync::logout($sessionID); $this->assertEquals(0, $xml->updated[0]->count()); }
public function testFormatBibMultiple() { foreach (self::$styles as $style) { $response = API::userGet(self::$config['userID'], "items?format=bib" . ($style == "default" ? "" : "&style=" . urlencode($style))); $this->assert200($response); $this->assertXmlStringEqualsXmlString(self::$multiResponses[$style], $response->getBody()); } }
private function _testPartialWriteFailureWithUnchanged($objectType) { API::userClear(self::$config['userID']); $objectTypePlural = API::getPluralObjectType($objectType); switch ($objectType) { case 'collection': $json1 = API::createCollection("Test", false, $this, 'jsonData'); $json2 = array("name" => str_repeat("1234567890", 6554)); $json3 = array("name" => "Test"); break; case 'item': $json1 = API::createItem("book", array("title" => "Title"), $this, 'jsonData'); $json2 = API::getItemTemplate('book'); $json3 = clone $json2; $json2->title = str_repeat("1234567890", 6554); break; case 'search': $conditions = array(array('condition' => 'title', 'operator' => 'contains', 'value' => 'value')); $json1 = API::createSearch("Name", $conditions, $this, 'jsonData'); $json2 = array("name" => str_repeat("1234567890", 6554), "conditions" => $conditions); $json3 = array("name" => "Test", "conditions" => $conditions); break; } $response = API::userPost(self::$config['userID'], "{$objectTypePlural}", json_encode([$json1, $json2, $json3]), array("Content-Type: application/json")); $this->assert200($response); $json = API::getJSONFromResponse($response); $this->assertUnchangedForObject($response, 0); $this->assert400ForObject($response, false, 1); $this->assert200ForObject($response, false, 2); $json = API::getJSONFromResponse($response); $response = API::userGet(self::$config['userID'], "{$objectTypePlural}?format=keys&key=" . self::$config['apiKey']); $this->assert200($response); $keys = explode("\n", trim($response->getBody())); $this->assertCount(2, $keys); foreach ($json['success'] as $key) { $this->assertContains($key, $keys); } }
public function testUnsupportedSettingMultiple() { $settingKey = "unsupportedSetting"; $json = array("tagColors" => array("value" => array("name" => "_READ", "color" => "#990000"), "version" => 0), $settingKey => array("value" => false, "version" => 0)); $libraryVersion = API::getLibraryVersion(); $response = API::userPut(self::$config['userID'], "settings/{$settingKey}", json_encode($json), array("Content-Type: application/json")); $this->assert400($response, "Invalid setting '{$settingKey}'"); // Valid setting shouldn't exist, and library version should be unchanged $response = API::userGet(self::$config['userID'], "settings/{$settingKey}"); $this->assert404($response); $this->assertEquals($libraryVersion, API::getLibraryVersion()); }
public function testKeyNoteAccess() { API::userClear(self::$config['userID']); API::setKeyOption(self::$config['userID'], self::$config['apiKey'], 'libraryNotes', 1); $keys = array(); $topLevelKeys = array(); $bookKeys = array(); $key = API::createItem('book', array("title" => "A"), $this, 'key'); $keys[] = $key; $topKeys[] = $key; $bookKeys[] = $key; $key = API::createNoteItem("B", false, $this, 'key'); $keys[] = $key; $topKeys[] = $key; $key = API::createNoteItem("C", false, $this, 'key'); $keys[] = $key; $topKeys[] = $key; $key = API::createNoteItem("D", false, $this, 'key'); $keys[] = $key; $topKeys[] = $key; $key = API::createNoteItem("E", false, $this, 'key'); $keys[] = $key; $topKeys[] = $key; $key = API::createItem('book', array("title" => "F"), $this, 'key'); $keys[] = $key; $topKeys[] = $key; $bookKeys[] = $key; $key = API::createNoteItem("G", $key, $this, 'key'); $keys[] = $key; // Create collection and add items to it $response = API::userPost(self::$config['userID'], "collections", json_encode([["name" => "Test", "parentCollection" => false]]), array("Content-Type: application/json")); $this->assert200ForObject($response); $collectionKey = API::getFirstSuccessKeyFromResponse($response); $response = API::userPost(self::$config['userID'], "collections/{$collectionKey}/items", implode(" ", $topKeys)); $this->assert204($response); // // format=atom // // Root $response = API::userGet(self::$config['userID'], "items"); $this->assertNumResults(sizeOf($keys), $response); $this->assertTotalResults(sizeOf($keys), $response); // Top $response = API::userGet(self::$config['userID'], "items/top"); $this->assertNumResults(sizeOf($topKeys), $response); $this->assertTotalResults(sizeOf($topKeys), $response); // Collection $response = API::userGet(self::$config['userID'], "collections/{$collectionKey}/items/top"); $this->assertNumResults(sizeOf($topKeys), $response); $this->assertTotalResults(sizeOf($topKeys), $response); // // format=keys // // Root $response = API::userGet(self::$config['userID'], "items?format=keys"); $this->assert200($response); $this->assertCount(sizeOf($keys), explode("\n", trim($response->getBody()))); // Top $response = API::userGet(self::$config['userID'], "items/top?format=keys"); $this->assert200($response); $this->assertCount(sizeOf($topKeys), explode("\n", trim($response->getBody()))); // Collection $response = API::userGet(self::$config['userID'], "collections/{$collectionKey}/items/top?format=keys"); $this->assert200($response); $this->assertCount(sizeOf($topKeys), explode("\n", trim($response->getBody()))); // Remove notes privilege from key API::setKeyOption(self::$config['userID'], self::$config['apiKey'], 'libraryNotes', 0); // // format=json // // totalResults with limit $response = API::userGet(self::$config['userID'], "items?limit=1"); $this->assertNumResults(1, $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // And without limit $response = API::userGet(self::$config['userID'], "items"); $this->assertNumResults(sizeOf($bookKeys), $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // Top $response = API::userGet(self::$config['userID'], "items/top"); $this->assertNumResults(sizeOf($bookKeys), $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // Collection $response = API::userGet(self::$config['userID'], "collections/{$collectionKey}/items"); $this->assertNumResults(sizeOf($bookKeys), $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // // format=atom // // totalResults with limit $response = API::userGet(self::$config['userID'], "items?format=atom&limit=1"); $this->assertNumResults(1, $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // And without limit $response = API::userGet(self::$config['userID'], "items?format=atom"); $this->assertNumResults(sizeOf($bookKeys), $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // Top $response = API::userGet(self::$config['userID'], "items/top?format=atom"); $this->assertNumResults(sizeOf($bookKeys), $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // Collection $response = API::userGet(self::$config['userID'], "collections/{$collectionKey}/items?format=atom"); $this->assertNumResults(sizeOf($bookKeys), $response); $this->assertTotalResults(sizeOf($bookKeys), $response); // // format=keys // $response = API::userGet(self::$config['userID'], "items?format=keys"); $keys = explode("\n", trim($response->getBody())); sort($keys); $this->assertEmpty(array_merge(array_diff($bookKeys, $keys), array_diff($keys, $bookKeys))); }
public function testSortDirection() { API::userClear(self::$config['userID']); // Setup $dataArray = []; $dataArray[] = API::createItem("book", ['title' => "B", 'creators' => [["creatorType" => "author", "name" => "B"]], 'dateAdded' => '2014-02-05T00:00:00Z', 'dateModified' => '2014-04-05T01:00:00Z'], $this, 'jsonData'); $dataArray[] = API::createItem("journalArticle", ['title' => "A", 'creators' => [["creatorType" => "author", "name" => "A"]], 'dateAdded' => '2014-02-04T00:00:00Z', 'dateModified' => '2014-01-04T01:00:00Z'], $this, 'jsonData'); $dataArray[] = API::createItem("newspaperArticle", ['title' => "F", 'creators' => [["creatorType" => "author", "name" => "F"]], 'dateAdded' => '2014-02-03T00:00:00Z', 'dateModified' => '2014-02-03T01:00:00Z'], $this, 'jsonData'); $dataArray[] = API::createItem("book", ['title' => "C", 'creators' => [["creatorType" => "author", "name" => "C"]], 'dateAdded' => '2014-02-02T00:00:00Z', 'dateModified' => '2014-03-02T01:00:00Z'], $this, 'jsonData'); // Get sorted keys usort($dataArray, function ($a, $b) { return strcmp($a['dateAdded'], $b['dateAdded']); }); $keysByDateAddedAscending = array_map(function ($data) { return $data['key']; }, $dataArray); $keysByDateAddedDescending = array_reverse($keysByDateAddedAscending); // Ascending $response = API::userGet(self::$config['userID'], "items?format=keys&sort=dateAdded&direction=asc"); $this->assert200($response); $this->assertEquals($keysByDateAddedAscending, explode("\n", trim($response->getBody()))); $response = API::userGet(self::$config['userID'], "items?format=json&sort=dateAdded&direction=asc"); $this->assert200($response); $json = API::getJSONFromResponse($response); $keys = array_map(function ($val) { return $val['key']; }, $json); $this->assertEquals($keysByDateAddedAscending, $keys); $response = API::userGet(self::$config['userID'], "items?format=atom&sort=dateAdded&direction=asc"); $this->assert200($response); $xml = API::getXMLFromResponse($response); $keys = array_map(function ($val) { return (string) $val; }, $xml->xpath('//atom:entry/zapi:key')); $this->assertEquals($keysByDateAddedAscending, $keys); // Ascending using old 'order'/'sort' instead of 'sort'/'direction' $response = API::userGet(self::$config['userID'], "items?format=keys&order=dateAdded&sort=asc"); $this->assert200($response); $this->assertEquals($keysByDateAddedAscending, explode("\n", trim($response->getBody()))); $response = API::userGet(self::$config['userID'], "items?format=json&order=dateAdded&sort=asc"); $this->assert200($response); $json = API::getJSONFromResponse($response); $keys = array_map(function ($val) { return $val['key']; }, $json); $this->assertEquals($keysByDateAddedAscending, $keys); $response = API::userGet(self::$config['userID'], "items?format=atom&order=dateAdded&sort=asc"); $this->assert200($response); $xml = API::getXMLFromResponse($response); $keys = array_map(function ($val) { return (string) $val; }, $xml->xpath('//atom:entry/zapi:key')); $this->assertEquals($keysByDateAddedAscending, $keys); // Deprecated 'order'/'sort', but the wrong way $response = API::userGet(self::$config['userID'], "items?format=keys&sort=dateAdded&order=asc"); $this->assert200($response); $this->assertEquals($keysByDateAddedAscending, explode("\n", trim($response->getBody()))); // Descending $response = API::userGet(self::$config['userID'], "items?format=keys&sort=dateAdded&direction=desc"); $this->assert200($response); $this->assertEquals($keysByDateAddedDescending, explode("\n", trim($response->getBody()))); $response = API::userGet(self::$config['userID'], "items?format=json&sort=dateAdded&direction=desc"); $this->assert200($response); $json = API::getJSONFromResponse($response); $keys = array_map(function ($val) { return $val['key']; }, $json); $this->assertEquals($keysByDateAddedDescending, $keys); $response = API::userGet(self::$config['userID'], "items?format=atom&sort=dateAdded&direction=desc"); $this->assert200($response); $xml = API::getXMLFromResponse($response); $keys = array_map(function ($val) { return (string) $val; }, $xml->xpath('//atom:entry/zapi:key')); $this->assertEquals($keysByDateAddedDescending, $keys); // Descending $response = API::userGet(self::$config['userID'], "items?format=keys&order=dateAdded&sort=desc"); $this->assert200($response); $this->assertEquals($keysByDateAddedDescending, explode("\n", trim($response->getBody()))); $response = API::userGet(self::$config['userID'], "items?format=json&order=dateAdded&sort=desc"); $this->assert200($response); $json = API::getJSONFromResponse($response); $keys = array_map(function ($val) { return $val['key']; }, $json); $this->assertEquals($keysByDateAddedDescending, $keys); $response = API::userGet(self::$config['userID'], "items?format=atom&order=dateAdded&sort=desc"); $this->assert200($response); $xml = API::getXMLFromResponse($response); $keys = array_map(function ($val) { return (string) $val; }, $xml->xpath('//atom:entry/zapi:key')); $this->assertEquals($keysByDateAddedDescending, $keys); }
public function testLastStorageSyncNoAuthorization() { API::useAPIKey(false); $response = API::userGet( self::$config['userID'], "laststoragesync" ); $this->assert401($response); }
public function testMultiTagDelete() { $tags1 = array("a", "aa", "b"); $tags2 = array("b", "c", "cc"); $tags3 = array("Foo"); API::createItem("book", array("tags" => array_map(function ($tag) { return array("tag" => $tag); }, $tags1)), $this, 'key'); API::createItem("book", array("tags" => array_map(function ($tag) { return array("tag" => $tag, "type" => 1); }, $tags2)), $this, 'key'); API::createItem("book", array("tags" => array_map(function ($tag) { return array("tag" => $tag); }, $tags3)), $this, 'key'); $libraryVersion = API::getLibraryVersion(); // Missing version header $response = API::userDelete(self::$config['userID'], "tags?tag=" . implode("%20||%20", array_merge($tags1, $tags2))); $this->assert428($response); // Outdated version header $response = API::userDelete(self::$config['userID'], "tags?tag=" . implode("%20||%20", array_merge($tags1, $tags2)), array("If-Unmodified-Since-Version: " . ($libraryVersion - 1))); $this->assert412($response); // Delete $response = API::userDelete(self::$config['userID'], "tags?tag=" . implode("%20||%20", array_merge($tags1, $tags2)), array("If-Unmodified-Since-Version: {$libraryVersion}")); $this->assert204($response); // Make sure they're gone $response = API::userGet(self::$config['userID'], "tags?tag=" . implode("%20||%20", array_merge($tags1, $tags2, $tags3))); $this->assert200($response); $this->assertNumResults(1, $response); }
public function testItemQuickSearchOrderByDate() { $title1 = "Test Title"; $title2 = "Another Title"; $keys = []; $keys[] = API::createItem("book", ['title' => $title1, 'date' => "February 12, 2013"], $this, 'key'); $keys[] = API::createItem("journalArticle", ['title' => $title2, 'date' => "November 25, 2012"], $this, 'key'); // Search for one by title $response = API::userGet(self::$config['userID'], "items?q=" . urlencode($title1)); $this->assert200($response); $this->assertNumResults(1, $response); $json = API::getJSONFromResponse($response); $this->assertEquals($keys[0], $json[0]['key']); // Search by both by title, date asc $response = API::userGet(self::$config['userID'], "items?q=title&sort=date&direction=asc"); $this->assert200($response); $this->assertNumResults(2, $response); $json = API::getJSONFromResponse($response); $this->assertEquals($keys[1], $json[0]['key']); $this->assertEquals($keys[0], $json[1]['key']); // Search by both by title, date asc, with old-style parameters $response = API::userGet(self::$config['userID'], "items?q=title&order=date&sort=asc"); $this->assert200($response); $this->assertNumResults(2, $response); $json = API::getJSONFromResponse($response); $this->assertEquals($keys[1], $json[0]['key']); $this->assertEquals($keys[0], $json[1]['key']); // Search by both by title, date desc $response = API::userGet(self::$config['userID'], "items?q=title&sort=date&direction=desc"); $this->assert200($response); $this->assertNumResults(2, $response); $json = API::getJSONFromResponse($response); $this->assertEquals($keys[0], $json[0]['key']); $this->assertEquals($keys[1], $json[1]['key']); // Search by both by title, date desc, with old-style parameters $response = API::userGet(self::$config['userID'], "items?q=title&order=date&sort=desc"); $this->assert200($response); $this->assertNumResults(2, $response); $json = API::getJSONFromResponse($response); $this->assertEquals($keys[0], $json[0]['key']); $this->assertEquals($keys[1], $json[1]['key']); }
public function testKeyCreateAndDelete() { API::useAPIKey(""); $name = "Test " . uniqid(); // Can't create as user $response = API::userPost(self::$config['userID'], 'keys', json_encode(['name' => $name, 'access' => ['user' => ['library' => true]]])); $this->assert403($response); // Create as root $response = API::userPost(self::$config['userID'], 'keys', json_encode(['name' => $name, 'access' => ['user' => ['library' => true]]]), [], ["username" => self::$config['rootUsername'], "password" => self::$config['rootPassword']]); $this->assert201($response); $json = API::getJSONFromResponse($response); $key = $json['key']; $this->assertEquals($json['name'], $name); $this->assertEquals(['user' => ['library' => true, 'files' => true]], $json['access']); // Delete anonymously (with embedded key) $response = API::userDelete(self::$config['userID'], "keys/{$key}"); $this->assert204($response); $response = API::userGet(self::$config['userID'], "keys/{$key}"); $this->assert404($response); }
/** * Changing a group's metadata should change its ETag */ public function testUpdateMetadataAtom() { $response = API::userGet(self::$config['userID'], "groups?content=json&key=" . self::$config['apiKey']); $this->assert200($response); // Get group API URI and version $xml = API::getXMLFromResponse($response); $xml->registerXPathNamespace('atom', 'http://www.w3.org/2005/Atom'); $xml->registerXPathNamespace('zapi', 'http://zotero.org/ns/api'); $groupID = (string) array_shift($xml->xpath("//atom:entry/zapi:groupID")); $url = (string) array_shift($xml->xpath("//atom:entry/atom:link[@rel='self']/@href")); $url = str_replace(self::$config['apiURLPrefix'], '', $url); $version = json_decode(API::parseDataFromAtomEntry($xml)['content'], true)['version']; // Make sure format=versions returns the same ETag $response = API::userGet(self::$config['userID'], "groups?format=versions&key=" . self::$config['apiKey']); $this->assert200($response); $json = json_decode($response->getBody()); $this->assertEquals($version, $json->{$groupID}); // Update group metadata $json = json_decode(array_shift($xml->xpath("//atom:entry/atom:content"))); $xml = new SimpleXMLElement("<group/>"); foreach ($json as $key => $val) { switch ($key) { case 'id': case 'members': continue; case 'name': $name = "My Test Group " . uniqid(); $xml['name'] = $name; break; case 'description': $description = "This is a test description " . uniqid(); $xml->{$key} = $description; break; case 'url': $urlField = "http://example.com/" . uniqid(); $xml->{$key} = $urlField; break; default: $xml[$key] = $val; } } $xml = trim(preg_replace('/^<\\?xml.+\\n/', "", $xml->asXML())); $response = API::put($url, $xml, array("Content-Type: text/xml"), array("username" => self::$config['rootUsername'], "password" => self::$config['rootPassword'])); $this->assert200($response); $xml = API::getXMLFromResponse($response); $xml->registerXPathNamespace('zxfer', 'http://zotero.org/ns/transfer'); $group = $xml->xpath('//atom:entry/atom:content/zxfer:group'); $this->assertCount(1, $group); $this->assertEquals($name, $group[0]['name']); $response = API::userGet(self::$config['userID'], "groups?format=versions&key=" . self::$config['apiKey']); $this->assert200($response); $json = json_decode($response->getBody()); $newVersion = $json->{$groupID}; $this->assertNotEquals($version, $newVersion); // Check ETag header on individual group request $response = API::groupGet($groupID, "?content=json&key=" . self::$config['apiKey']); $this->assert200($response); $this->assertEquals($newVersion, $response->getHeader('Last-Modified-Version')); $json = json_decode(API::getContentFromResponse($response)); $this->assertEquals($name, $json->name); $this->assertEquals($description, $json->description); $this->assertEquals($urlField, $json->url); }
private function _testTagsSince($param) { $tags1 = array("a", "aa", "b"); $tags2 = array("b", "c", "cc"); $data1 = API::createItem("book", array("tags" => array_map(function ($tag) { return array("tag" => $tag); }, $tags1)), $this, 'jsonData'); $data2 = API::createItem("book", array("tags" => array_map(function ($tag) { return array("tag" => $tag); }, $tags2)), $this, 'jsonData'); // Only newly added tags should be included in 'since', // not previously added tags or tags added to items $response = API::userGet(self::$config['userID'], "tags?{$param}=" . $data1['version']); $this->assertNumResults(2, $response); // Deleting an item shouldn't update associated tag versions $response = API::userDelete(self::$config['userID'], "items/{$data1['key']}", array("If-Unmodified-Since-Version: " . $data1['version'])); $this->assert204($response); $response = API::userGet(self::$config['userID'], "tags?{$param}=" . $data1['version']); $this->assertNumResults(2, $response); $libraryVersion = $response->getHeader("Last-Modified-Version"); $response = API::userGet(self::$config['userID'], "tags?{$param}=" . $libraryVersion); $this->assertNumResults(0, $response); }
/** * Revoke access for a group from an API key that has access to all groups */ public function testKeyRemoveLibraryFromAllGroupsNotification() { API::useAPIKey(""); $removedGroup = self::$config['ownedPrivateGroupID']; $json = $this->createKeyWithAllGroupAccess(self::$config['userID']); $apiKey = $json['key']; try { // Get list of available groups API::useAPIKey($apiKey); $response = API::userGet(self::$config['userID'], 'groups'); $groupIDs = array_map(function ($group) { return $group['id']; }, API::getJSONFromResponse($response)); // Remove one group, and replace access array with new set $groupIDs = array_diff($groupIDs, [$removedGroup]); unset($json['access']['groups']['all']); foreach ($groupIDs as $groupID) { $json['access']['groups'][$groupID]['library'] = true; } // Post new JSON, which should trigger topicRemoved for the removed group API::useAPIKey(""); $response = API::superPut("keys/{$apiKey}", json_encode($json)); $this->assert200($response); $this->assertCountNotifications(1, $response); foreach ($groupIDs as $groupID) { $this->assertHasNotification(['event' => 'topicRemoved', 'apiKey' => $apiKey, 'topic' => '/groups/' . $removedGroup], $response); } } finally { $response = API::superDelete("keys/{$apiKey}"); } }