public static function setUpBeforeClass() { parent::setUpBeforeClass(); API::userClear(self::$config['userID']); // Create test data $key = API::createItem("book", array("title" => "Title", "creators" => array(array("creatorType" => "author", "firstName" => "First", "lastName" => "Last"))), null, 'key'); self::$items[$key] = '<content xmlns:zapi="http://zotero.org/ns/api" type="application/xml"><zapi:subcontent zapi:type="bib"><div xmlns="http://www.w3.org/1999/xhtml" class="csl-bib-body" style="line-height: 1.35; padding-left: 2em; text-indent:-2em;"><div class="csl-entry">Last, First. <i>Title</i>, n.d.</div></div></zapi:subcontent><zapi:subcontent zapi:type="json">' . \Zotero_Utilities::formatJSON(json_decode('{"itemKey":"","itemVersion":0,"itemType":"book","title":"Title","creators":[{"creatorType":"author","firstName":"First","lastName":"Last"}],"abstractNote":"","series":"","seriesNumber":"","volume":"","numberOfVolumes":"","edition":"","place":"","publisher":"","date":"","numPages":"","language":"","ISBN":"","shortTitle":"","url":"","accessDate":"","archive":"","archiveLocation":"","libraryCatalog":"","callNumber":"","rights":"","extra":"","tags":[],"collections":[],"relations":{}}')) . '</zapi:subcontent></content>'; $key = API::createItem("book", array("title" => "Title 2", "creators" => array(array("creatorType" => "author", "firstName" => "First", "lastName" => "Last"), array("creatorType" => "editor", "firstName" => "Ed", "lastName" => "McEditor"))), null, 'key'); self::$items[$key] = '<content xmlns:zapi="http://zotero.org/ns/api" type="application/xml"><zapi:subcontent zapi:type="bib"><div xmlns="http://www.w3.org/1999/xhtml" class="csl-bib-body" style="line-height: 1.35; padding-left: 2em; text-indent:-2em;"><div class="csl-entry">Last, First. <i>Title 2</i>. Edited by Ed McEditor, n.d.</div></div></zapi:subcontent><zapi:subcontent zapi:type="json">' . \Zotero_Utilities::formatJSON(json_decode('{"itemKey":"","itemVersion":0,"itemType":"book","title":"Title 2","creators":[{"creatorType":"author","firstName":"First","lastName":"Last"},{"creatorType":"editor","firstName":"Ed","lastName":"McEditor"}],"abstractNote":"","series":"","seriesNumber":"","volume":"","numberOfVolumes":"","edition":"","place":"","publisher":"","date":"","numPages":"","language":"","ISBN":"","shortTitle":"","url":"","accessDate":"","archive":"","archiveLocation":"","libraryCatalog":"","callNumber":"","rights":"","extra":"","tags":[],"collections":[],"relations":{}}')) . '</zapi:subcontent></content>'; }
public function testInvalidCharacters() { $data = array('title' => "A" . chr(0) . "A", 'creators' => array(array('creatorType' => "author", 'name' => "B" . chr(1) . "B")), 'tags' => array(array('tag' => "C" . chr(2) . "C"))); $xml = API::createItem("book", $data, $this, 'atom'); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $this->assertEquals("AA", $json->title); $this->assertEquals("BB", $json->creators[0]->name); $this->assertEquals("CC", $json->tags[0]->tag); }
public static function setUpBeforeClass() { parent::setUpBeforeClass(); API::userClear(self::$config['userID']); // Create test data $key = API::createItem("book", array("title" => "Title", "creators" => array(array("creatorType" => "author", "firstName" => "First", "lastName" => "Last"))), null, 'key'); self::$items[$key] = array("citation" => array("default" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="citation" type="xhtml"><span xmlns="http://www.w3.org/1999/xhtml">Last, <i>Title</i>.</span></content>', "apa" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="citation" type="xhtml"><span xmlns="http://www.w3.org/1999/xhtml">(Last, n.d.)</span></content>'), "bib" => array("default" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="bib" type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml" class="csl-bib-body" style="line-height: 1.35; padding-left: 2em; text-indent:-2em;"><div class="csl-entry">Last, First. <i>Title</i>, n.d.</div></div></content>', "apa" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="bib" type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml" class="csl-bib-body" style="line-height: 2; padding-left: 2em; text-indent:-2em;"><div class="csl-entry">Last, F. (n.d.). <i>Title</i>.</div></div></content>')); $key = API::createItem("book", array("title" => "Title 2", "creators" => array(array("creatorType" => "author", "firstName" => "First", "lastName" => "Last"), array("creatorType" => "editor", "firstName" => "Ed", "lastName" => "McEditor"))), null, 'key'); self::$items[$key] = array("citation" => array("default" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="citation" type="xhtml"><span xmlns="http://www.w3.org/1999/xhtml">Last, <i>Title 2</i>.</span></content>', "apa" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="citation" type="xhtml"><span xmlns="http://www.w3.org/1999/xhtml">(Last, n.d.)</span></content>'), "bib" => array("default" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="bib" type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml" class="csl-bib-body" style="line-height: 1.35; padding-left: 2em; text-indent:-2em;"><div class="csl-entry">Last, First. <i>Title 2</i>. Edited by Ed McEditor, n.d.</div></div></content>', "apa" => '<content xmlns:zapi="http://zotero.org/ns/api" zapi:type="bib" type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml" class="csl-bib-body" style="line-height: 2; padding-left: 2em; text-indent:-2em;"><div class="csl-entry">Last, F. (n.d.). <i>Title 2</i>. (E. McEditor, Ed.).</div></div></content>')); }
/** * 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}?key=" . self::$config['apiKey'] . "&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 static function setUpBeforeClass() { parent::setUpBeforeClass(); API::userClear(self::$config['userID']); // // Collections // /*for ($i=0; $i<5; $i++) { self::$collectionKeys[] = API::createCollection("Test", false, null, 'key'); }*/ // // Items // $titles = self::$titles; $names = self::$names; for ($i = 0; $i < sizeOf(self::$titles) - 2; $i++) { $key = API::createItem("book", ["title" => array_shift($titles), "creators" => [["creatorType" => "author", "name" => array_shift($names)]]], null, 'key'); // Child attachments if (!is_null(self::$attachmentTitles[$i])) { self::$childAttachmentKeys[] = API::createAttachmentItem("imported_file", ["title" => self::$attachmentTitles[$i]], $key, null, 'key'); } // Child notes if (!is_null(self::$notes[$i])) { self::$childNoteKeys[] = API::createNoteItem(self::$notes[$i], $key, null, 'key'); } self::$itemKeys[] = $key; } // Top-level attachment self::$itemKeys[] = API::createAttachmentItem("imported_file", ["title" => array_shift($titles)], false, null, 'key'); // Top-level note self::$itemKeys[] = API::createNoteItem(array_shift($titles), false, null, 'key'); // // Searches // /*for ($i=0; $i<5; $i++) { self::$searchKeys[] = API::createSearch("Test", 'default', null, 'key'); }*/ }
public function testCreatorSummary() { $xml = API::createItem("book", array("creators" => array(array("creatorType" => "author", "name" => "Test"))), $this); $data = API::parseDataFromAtomEntry($xml); $itemKey = $data['key']; $json = json_decode($data['content'], true); $creatorSummary = (string) array_shift($xml->xpath('//atom:entry/zapi:creatorSummary')); $this->assertEquals("Test", $creatorSummary); $json['creators'][] = array("creatorType" => "author", "firstName" => "Alice", "lastName" => "Foo"); $response = API::userPut(self::$config['userID'], "items/{$itemKey}?key=" . self::$config['apiKey'], json_encode($json)); $this->assert204($response); $xml = API::getItemXML($itemKey); $creatorSummary = (string) array_shift($xml->xpath('//atom:entry/zapi:creatorSummary')); $this->assertEquals("Test and Foo", $creatorSummary); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content'], true); $json['creators'][] = array("creatorType" => "author", "firstName" => "Bob", "lastName" => "Bar"); $response = API::userPut(self::$config['userID'], "items/{$itemKey}?key=" . self::$config['apiKey'], json_encode($json)); $this->assert204($response); $xml = API::getItemXML($itemKey); $creatorSummary = (string) array_shift($xml->xpath('//atom:entry/zapi:creatorSummary')); $this->assertEquals("Test et al.", $creatorSummary); }
public function testUnicodeTitle() { $title = "Tést"; $xml = API::createItem("book", array("title" => $title), $this); $data = API::parseDataFromAtomEntry($xml); $key = $data['key']; // Test entry $response = API::userGet(self::$config['userID'], "items/{$key}?key=" . self::$config['apiKey'] . "&content=json"); $this->assertContains('"title": "Tést"', $response->getBody()); // Test feed $response = API::userGet(self::$config['userID'], "items?key=" . self::$config['apiKey'] . "&content=json"); $this->assertContains('"title": "Tést"', $response->getBody()); }
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?key=" . self::$config['apiKey'] . "&content=json&q=" . urlencode($title1)); $this->assert200($response); $this->assertNumResults(1, $response); $xml = API::getXMLFromResponse($response); $xpath = $xml->xpath('//atom:entry/zapi:key'); $key = (string) array_shift($xpath); $this->assertEquals($keys[0], $key); // Search by both by title, date asc $response = API::userGet(self::$config['userID'], "items?key=" . self::$config['apiKey'] . "&content=json&q=title&order=date&sort=asc"); $this->assert200($response); $this->assertNumResults(2, $response); $xml = API::getXMLFromResponse($response); $xpath = $xml->xpath('//atom:entry/zapi:key'); $key = (string) array_shift($xpath); $this->assertEquals($keys[1], $key); $key = (string) array_shift($xpath); $this->assertEquals($keys[0], $key); // Search by both by title, date desc $response = API::userGet(self::$config['userID'], "items?key=" . self::$config['apiKey'] . "&content=json&q=title&order=date&sort=desc"); $this->assert200($response); $this->assertNumResults(2, $response); $xml = API::getXMLFromResponse($response); $xpath = $xml->xpath('//atom:entry/zapi:key'); $key = (string) array_shift($xpath); $this->assertEquals($keys[0], $key); $key = (string) array_shift($xpath); $this->assertEquals($keys[1], $key); }
public function testSyncUploadUnchanged() { $data1 = API::createItem("audioRecording", array("title" => "Test", "relations" => array('owl:sameAs' => 'http://zotero.org/groups/1/items/AAAAAAAA')), null, 'data'); // dc:relation already exists, so item shouldn't change $data2 = API::createItem("interview", array("relations" => array('dc:relation' => 'http://zotero.org/users/' . self::$config['userID'] . '/items/' . $data1['key'])), null, 'data'); // Upload unchanged via sync $xml = Sync::updated(self::$sessionID); $updateKey = $xml['updateKey']; $lastSyncTimestamp = $xml['timestamp']; $itemXML1 = array_shift($xml->updated[0]->items[0]->xpath("item[@key='{$data1['key']}']")); $itemXML2 = array_shift($xml->updated[0]->items[0]->xpath("item[@key='{$data2['key']}']")); $itemXML1['libraryID'] = self::$config['libraryID']; $itemXML2['libraryID'] = self::$config['libraryID']; $xmlstr = '<data version="9">' . '<items>' . $itemXML1->asXML() . $itemXML2->asXML() . '</items>' . '</data>'; $response = Sync::upload(self::$sessionID, $updateKey, $xmlstr); Sync::waitForUpload(self::$sessionID, $response, $this); // Check via API to make sure they're the same $response = API::userGet(self::$config['userID'], "items?key=" . self::$config['apiKey'] . "&format=versions"); $json = API::getJSONFromResponse($response); $this->assertEquals($data1['version'], $json[$data1['key']]); $this->assertEquals($data2['version'], $json[$data2['key']]); }
public function testCircularRelatedItems() { $parentKey = API::createItem("book", false, null, 'key'); $noteKeys = [API::createNoteItem("Note 1", $parentKey, null, 'key'), API::createNoteItem("Note 2", $parentKey, null, 'key'), API::createNoteItem("Note 3", $parentKey, null, 'key'), API::createNoteItem("Note 4", $parentKey, null, 'key')]; $xml = Sync::updated(self::$sessionID); $updateKey = $xml['updateKey']; $note1XML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[0]}']")); $note2XML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[1]}']")); $note3XML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[2]}']")); $note4XML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[3]}']")); $note1XML['libraryID'] = self::$config['libraryID']; $note2XML['libraryID'] = self::$config['libraryID']; $note3XML['libraryID'] = self::$config['libraryID']; $note4XML['libraryID'] = self::$config['libraryID']; $note1XML->related = implode(' ', [$parentKey, (string) $note2XML['key'], (string) $note3XML['key'], (string) $note4XML['key']]); $note2XML->related = implode(' ', [$parentKey, (string) $note1XML['key'], (string) $note3XML['key'], (string) $note4XML['key']]); $note3XML->related = implode(' ', [$parentKey, (string) $note1XML['key'], (string) $note2XML['key'], (string) $note4XML['key']]); $note4XML->related = implode(' ', [$parentKey, (string) $note1XML['key'], (string) $note2XML['key'], (string) $note3XML['key']]); $xmlstr = '<data version="9">' . '<items>' . $note1XML->asXML() . $note2XML->asXML() . $note3XML->asXML() . $note4XML->asXML() . '</items>' . '</data>'; $response = Sync::upload(self::$sessionID, $updateKey, $xmlstr); Sync::waitForUpload(self::$sessionID, $response, $this); $xml = Sync::updated(self::$sessionID); $noteXML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[0]}']")); $keys = split(' ', $noteXML->related); $this->assertCount(4, $keys); $this->assertContains($parentKey, $keys); $this->assertContains((string) $noteKeys[1], $keys); $this->assertContains((string) $noteKeys[2], $keys); $this->assertContains((string) $noteKeys[3], $keys); $noteXML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[1]}']")); $keys = split(' ', $noteXML->related); $this->assertCount(4, $keys); $this->assertContains($parentKey, $keys); $this->assertContains((string) $noteKeys[0], $keys); $this->assertContains((string) $noteKeys[2], $keys); $this->assertContains((string) $noteKeys[3], $keys); $noteXML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[2]}']")); $keys = split(' ', $noteXML->related); $this->assertCount(4, $keys); $this->assertContains($parentKey, $keys); $this->assertContains((string) $noteKeys[0], $keys); $this->assertContains((string) $noteKeys[1], $keys); $this->assertContains((string) $noteKeys[3], $keys); $noteXML = array_shift($xml->updated[0]->items->xpath("//item[@key = '{$noteKeys[3]}']")); $keys = split(' ', $noteXML->related); $this->assertCount(4, $keys); $this->assertContains($parentKey, $keys); $this->assertContains((string) $noteKeys[0], $keys); $this->assertContains((string) $noteKeys[1], $keys); $this->assertContains((string) $noteKeys[2], $keys); }
private function _testPartialWriteFailureWithUnchanged($objectType) { API::userClear(self::$config['userID']); $objectTypePlural = API::getPluralObjectType($objectType); switch ($objectType) { case 'collection': $data = API::createCollection("Test", false, $this, 'data'); $json1 = json_decode($data['content']); $json2 = array("name" => str_repeat("1234567890", 6554)); $json3 = array("name" => "Test"); break; case 'item': $data = API::createItem("book", array("title" => "Title"), $this, 'data'); $json1 = json_decode($data['content']); $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')); $data = API::createSearch("Name", $conditions, $this, 'data'); $json1 = json_decode($data['content']); $json2 = array("name" => str_repeat("1234567890", 6554), "conditions" => $conditions); $json3 = array("name" => "Test", "conditions" => $conditions); break; } $response = API::userPost(self::$config['userID'], "{$objectTypePlural}?key=" . self::$config['apiKey'], json_encode(array("{$objectTypePlural}" => array($json1, $json2, $json3))), array("Content-Type: application/json")); $this->assert200($response); $json = API::getJSONFromResponse($response); $this->assertUnchangedForObject($response, false, 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); } }
/** * When modifying a tag on an item, only the item itself should have its * version updated, not other items that had (and still have) the same tag */ public function testTagAddItemVersionChange() { $data1 = API::createItem("book", array("tags" => array(array("tag" => "a"), array("tag" => "b"))), $this, 'data'); $json1 = json_decode($data1['content'], true); $version1 = $data1['version']; $data2 = API::createItem("book", array("tags" => array(array("tag" => "a"), array("tag" => "c"))), $this, 'data'); $json2 = json_decode($data2['content'], true); $version2 = $data2['version']; // Remove tag 'a' from item 1 $json1['tags'] = array(array("tag" => "d"), array("tag" => "c")); $response = API::postItem($json1); $this->assert200($response); // Item 1 version should be one greater than last update $xml1 = API::getItemXML($json1['itemKey']); $data1 = API::parseDataFromAtomEntry($xml1); $this->assertEquals($version2 + 1, $data1['version']); // Item 2 version shouldn't have changed $xml2 = API::getItemXML($json2['itemKey']); $data2 = API::parseDataFromAtomEntry($xml2); $this->assertEquals($version2, $data2['version']); }
public function testDeleteItemContent() { $key = API::createItem("book", false, $this, 'key'); $xml = API::createAttachmentItem("imported_file", [], $key, $this, 'atom'); $data = API::parseDataFromAtomEntry($xml); $content = "Ыюм мютат дэбетиз конвынёры эю, ку мэль жкрипта трактатоз.\nПро ут чтэт эрепюят граэкйж, дуо нэ выро рыкючабо пырикюлёз."; // Store content $response = API::userPut(self::$config['userID'], "items/{$data['key']}/fulltext?key=" . self::$config['apiKey'], json_encode(["content" => $content, "indexedPages" => 50]), array("Content-Type: application/json")); $this->assert204($response); $contentVersion = $response->getHeader("Last-Modified-Version"); // Retrieve it $response = API::userGet(self::$config['userID'], "items/{$data['key']}/fulltext?key=" . self::$config['apiKey']); $this->assert200($response); $json = json_decode($response->getBody(), true); $this->assertEquals($content, $json['content']); $this->assertEquals(50, $json['indexedPages']); // Set to empty string $response = API::userPut(self::$config['userID'], "items/{$data['key']}/fulltext?key=" . self::$config['apiKey'], json_encode(["content" => ""]), array("Content-Type: application/json")); $this->assert204($response); $this->assertGreaterThan($contentVersion, $response->getHeader("Last-Modified-Version")); // Make sure it's gone $response = API::userGet(self::$config['userID'], "items/{$data['key']}/fulltext?key=" . self::$config['apiKey']); $this->assert200($response); $json = json_decode($response->getBody(), true); $this->assertEquals("", $json['content']); $this->assertArrayNotHasKey("indexedPages", $json); }
public function testTagDeleteUnmodifiedItemChange() { $key = 'AAAAAAAA'; $xml = Sync::updated(self::$sessionID); $updateKey = (string) $xml['updateKey']; // Create item via sync $data = '<data version="9"><items><item libraryID="' . self::$config['libraryID'] . '" itemType="book" ' . 'dateAdded="2009-03-07 04:53:20" ' . 'dateModified="2009-03-07 04:54:09" ' . 'key="' . $key . '"/></items>' . '<tags><tag libraryID="' . self::$config['libraryID'] . '" name="Test" ' . 'dateAdded="2009-03-07 04:54:56" ' . 'dateModified="2009-03-07 04:54:56" ' . 'key="BBBBBBBB">' . '<items>' . $key . '</items>' . '</tag></tags></data>'; $response = Sync::upload(self::$sessionID, $updateKey, $data); Sync::waitForUpload(self::$sessionID, $response, $this); // Get item via API $response = API::userGet(self::$config['userID'], "items/{$key}?key=" . self::$config['apiKey'] . "&content=json"); $xml = API::getXMLFromResponse($response); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $originalVersion = $data['version']; $this->assertCount(1, $json->tags); $this->assertTrue(isset($json->tags[0]->tag)); $this->assertEquals("Test", $json->tags[0]->tag); // Get item via sync $xml = Sync::updated(self::$sessionID); $this->assertEquals(1, sizeOf($xml->updated->items->item)); $this->assertEquals(1, sizeOf($xml->updated->tags->tag)); $this->assertEquals(1, sizeOf($xml->updated->tags->tag[0]->items)); $lastsync = (int) $xml['timestamp']; usleep(1500000); // Increment the library version, since we're testing the // version below API::createItem('newspaperArticle', false, false, 'key'); $libraryVersion = API::getLibraryVersion(); $xml = Sync::updated(self::$sessionID); $updateKey = (string) $xml['updateKey']; // Delete tag via sync, with unmodified item $data = '<data version="9"><items><item libraryID="' . self::$config['libraryID'] . '" itemType="book" ' . 'dateAdded="2009-03-07 04:53:20" ' . 'dateModified="2009-03-07 04:54:09" ' . 'key="' . $key . '"/></items>' . '<deleted><tags><tag libraryID="' . self::$config['libraryID'] . '" key="BBBBBBBB"/>' . '</tags></deleted></data>'; $response = Sync::upload(self::$sessionID, $updateKey, $data); Sync::waitForUpload(self::$sessionID, $response, $this); // Get item via sync $xml = Sync::updated(self::$sessionID); $this->assertEquals(1, sizeOf(isset($xml->updated->tags->tag))); $this->assertFalse(isset($xml->updated->tags->tag[0]->items)); // Get item version via API $response = API::userGet(self::$config['userID'], "items/{$key}?key=" . self::$config['apiKey'] . "&content=json"); $xml = API::getXMLFromResponse($response); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $this->assertEquals(0, (int) array_shift($xml->xpath('/atom:entry/zapi:numTags'))); $this->assertCount(0, $json->tags); // New item version should be greater than before $this->assertGreaterThan($originalVersion, $data['version']); // And should be one more than previous version $this->assertEquals($libraryVersion + 1, $data['version']); // Only the newspaperArticle should be updated $xml = Sync::updated(self::$sessionID, $lastsync); $this->assertEquals(1, $xml->updated[0]->items[0]->count()); }
public function testDownloadCache() { $keys = []; $keys[] = API::createItem("book", false, false, 'key'); $keys[] = API::createItem("journalArticle", false, false, 'key'); $keys[] = API::createItem("newspaperArticle", false, false, 'key'); $keys[] = API::createItem("magazineArticle", false, false, 'key'); $keys[] = API::createItem("bookSection", false, false, 'key'); $keys[] = API::createItem("audioRecording", false, false, 'key'); $xml1 = Sync::updated(self::$sessionID); $xml2 = Sync::updated(self::$sessionID); $this->assertEquals(preg_replace('/timestamp="\\d+"/', 'timestamp="--"', $xml1->asXML()), preg_replace('/timestamp="\\d+"/', 'timestamp="--"', $xml2->asXML())); }
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); $xml = API::createItem("book", false, $this); $data = API::parseDataFromAtomEntry($xml); $key = $data['key']; $fileContentType = "text/html"; $fileCharset = "UTF-8"; $fileFilename = "file.html"; $fileModtime = time(); $xml = API::createAttachmentItem("imported_url", [], $key, $this); $data = API::parseDataFromAtomEntry($xml); $key = $data['key']; $version = $data['version']; $json = json_decode($data['content']); $json->contentType = $fileContentType; $json->charset = $fileCharset; $json->filename = $fileFilename; $response = API::userPut(self::$config['userID'], "items/{$key}?key=" . self::$config['apiKey'], 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/{$data['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/{$data['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/{$data['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/{$data['key']}?key=" . self::$config['apiKey'] . "&content=json"); $xml = API::getXMLFromResponse($response); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $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/{$data['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 testDeleteItemRelation() { $relations = array("owl:sameAs" => ["http://zotero.org/groups/1/items/AAAAAAAA", "http://zotero.org/groups/1/items/BBBBBBBB"], "dc:relation" => "http://zotero.org/users/" . self::$config['userID'] . "/items/AAAAAAAA"); $data = API::createItem("book", array("relations" => $relations), $this, 'data'); $json = json_decode($data['content'], true); // Remove a relation $json['relations']['owl:sameAs'] = $relations['owl:sameAs'] = $relations['owl:sameAs'][0]; $response = API::userPut(self::$config['userID'], "items/{$data['key']}?key=" . self::$config['apiKey'], json_encode($json)); $this->assert204($response); // Make sure it's gone $xml = API::getItemXML($data['key']); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content'], true); $this->assertCount(sizeOf($relations), $json['relations']); foreach ($relations as $predicate => $object) { $this->assertEquals($object, $json['relations'][$predicate]); } // Delete all $json['relations'] = new \stdClass(); $response = API::userPut(self::$config['userID'], "items/{$data['key']}?key=" . self::$config['apiKey'], json_encode($json)); $this->assert204($response); // Make sure they're gone $xml = API::getItemXML($data['key']); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content'], true); $this->assertCount(0, $json['relations']); }
public function testCollectionItems() { $collectionKey = API::createCollection('Test', false, $this, 'key'); $xml = API::createItem("book", array('collections' => array($collectionKey)), $this); $data = API::parseDataFromAtomEntry($xml); $itemKey1 = $data['key']; $itemVersion1 = $data['version']; $json = json_decode($data['content']); $this->assertEquals(array($collectionKey), $json->collections); $xml = API::createItem("journalArticle", array('collections' => array($collectionKey)), $this); $data = API::parseDataFromAtomEntry($xml); $itemKey2 = $data['key']; $itemVersion2 = $data['version']; $json = json_decode($data['content']); $this->assertEquals(array($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?key=" . self::$config['apiKey'] . "&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?key=" . self::$config['apiKey'] . "&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 testTagDeletePermissions() { API::userClear(self::$config['userID']); $xml = API::createItem('book', array("tags" => array(array("tag" => "A"))), $this); $libraryVersion = API::getLibraryVersion(); API::setKeyOption(self::$config['userID'], self::$config['apiKey'], 'libraryWrite', 0); $response = API::userDelete(self::$config['userID'], "tags?tag=A&key=" . self::$config['apiKey']); $this->assert403($response); API::setKeyOption(self::$config['userID'], self::$config['apiKey'], 'libraryWrite', 1); $response = API::userDelete(self::$config['userID'], "tags?tag=A&key=" . self::$config['apiKey'], array("If-Unmodified-Since-Version: {$libraryVersion}")); $this->assert204($response); }
private function _testUploadUnmodified($objectType) { $objectTypePlural = API::getPluralObjectType($objectType); switch ($objectType) { case 'collection': $xml = API::createCollection("Name", false, $this); break; case 'item': $xml = API::createItem("book", array("title" => "Title"), $this); break; case 'search': $xml = API::createSearch("Name", 'default', $this); break; } $version = (int) array_shift($xml->xpath('//atom:entry/zapi:version')); $this->assertNotEquals(0, $version); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $response = API::userPut(self::$config['userID'], "{$objectTypePlural}/{$data['key']}?key=" . self::$config['apiKey'], json_encode($json)); $this->assert204($response); $this->assertEquals($version, $response->getHeader("Last-Modified-Version")); switch ($objectType) { case 'collection': $xml = API::getCollectionXML($data['key']); break; case 'item': $xml = API::getItemXML($data['key']); break; case 'search': $xml = API::getSearchXML($data['key']); break; } $data = API::parseDataFromAtomEntry($xml); $this->assertEquals($version, $data['version']); }