public static function getDownloadURL(Zotero_Item $item, $ttl = 60) { if (!$item->isAttachment()) { throw new Exception("Item {$item->id} is not an attachment"); } $info = self::getLocalFileItemInfo($item); if (!$info) { return false; } $contentType = $item->attachmentMIMEType; $charset = $item->attachmentCharset; if ($charset) { // TEMP: Make sure charset is printable ASCII $charset = preg_replace('/[^A-Za-z0-9\\-]/', '', $charset); $contentType .= "; charset={$charset}"; } $s3Client = Z_Core::$AWS->get('s3'); try { $key = $info['hash']; $s3Client->headObject(['Bucket' => Z_CONFIG::$S3_BUCKET, 'Key' => $info['hash']]); } catch (\Aws\S3\Exception\NoSuchKeyException $e) { // Try legacy key format, with zip flag and filename try { $key = self::getPathPrefix($info['hash'], $info['zip']) . $info['filename']; $s3Client->headObject(['Bucket' => Z_CONFIG::$S3_BUCKET, 'Key' => $key]); } catch (\Aws\S3\Exception\NoSuchKeyException $e) { return false; } } return $s3Client->getCommand('GetObject', array('Bucket' => Z_CONFIG::$S3_BUCKET, 'Key' => $key, 'ResponseContentType' => $contentType))->createPresignedUrl("+{$ttl} seconds"); }
public function testExistsByLibraryAndKey() { $this->assertFalse(Zotero_Items::existsByLibraryAndKey(self::$config['userLibraryID'], "AAAAAAAA")); $item = new Zotero_Item(); $item->libraryID = self::$config['userLibraryID']; $item->itemTypeID = Zotero_ItemTypes::getID("book"); $item->save(); $key = $item->key; $this->assertTrue(Zotero_Items::existsByLibraryAndKey(self::$config['userLibraryID'], $key)); Zotero_Items::delete(self::$config['userLibraryID'], $key); $this->assertFalse(Zotero_Items::existsByLibraryAndKey(self::$config['userLibraryID'], $key)); }
public static function getDownloadURL(Zotero_Item $item, $ttl = 60) { if (!$item->isAttachment()) { throw new Exception("Item {$item->id} is not an attachment"); } $info = self::getLocalFileItemInfo($item); if (!$info) { return false; } $contentType = $item->attachmentMIMEType; $charset = $item->attachmentCharset; if ($charset) { // TEMP: Make sure charset is printable ASCII $charset = preg_replace('/[^A-Za-z0-9\\-]/', '', $charset); $contentType .= "; charset={$charset}"; } $s3Client = Z_Core::$AWS->createS3(); try { $key = $info['hash']; $s3Client->headObject(['Bucket' => Z_CONFIG::$S3_BUCKET, 'Key' => $info['hash']]); } catch (\Aws\S3\Exception\S3Exception $e) { // Supposed to be NoSuchKey according to // http://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#headobject, // but returning NotFound if ($e->getAwsErrorCode() == 'NoSuchKey' || $e->getAwsErrorCode() == 'NotFound') { // Try legacy key format, with zip flag and filename try { $key = self::getPathPrefix($info['hash'], $info['zip']) . $info['filename']; $s3Client->headObject(['Bucket' => Z_CONFIG::$S3_BUCKET, 'Key' => $key]); } catch (\Aws\S3\Exception\S3Exception $e) { if ($e->getAwsErrorCode() == 'NoSuchKey' || $e->getAwsErrorCode() == 'NotFound') { return false; } throw $e; } } else { throw $e; } } $cmd = $s3Client->getCommand('GetObject', ['Bucket' => Z_CONFIG::$S3_BUCKET, 'Key' => $key, 'ResponseContentType' => $contentType]); return (string) $s3Client->createPresignedRequest($cmd, "+{$ttl} seconds")->getUri(); }
public static function indexItem(Zotero_Item $item, $content, $stats = array()) { if (!$item->isAttachment()) { throw new Exception("Full-text content can only be added for attachments", Z_ERROR_INVALID_INPUT); } Zotero_DB::beginTransaction(); $libraryID = $item->libraryID; $key = $item->key; $version = Zotero_Libraries::getUpdatedVersion($item->libraryID); $timestamp = Zotero_DB::transactionInProgress() ? Zotero_DB::getTransactionTimestamp() : date("Y-m-d H:i:s"); // Add to MySQL for syncing, since Elasticsearch doesn't refresh immediately $sql = "REPLACE INTO itemFulltext ("; $fields = ["itemID", "version", "timestamp"]; $params = [$item->id, $version, $timestamp]; $sql .= implode(", ", $fields) . ") VALUES (" . implode(', ', array_fill(0, sizeOf($params), '?')) . ")"; Zotero_DB::query($sql, $params, Zotero_Shards::getByLibraryID($libraryID)); // Add to Elasticsearch self::indexItemInElasticsearch($libraryID, $key, $version, $timestamp, $content, $stats); Zotero_DB::commit(); }
private static function loadItems($libraryID, $itemIDs = array()) { $shardID = Zotero_Shards::getByLibraryID($libraryID); $sql = self::getPrimaryDataSQL() . "1"; // TODO: optimize if ($itemIDs) { foreach ($itemIDs as $itemID) { if (!is_int($itemID)) { throw new Exception("Invalid itemID {$itemID}"); } } $sql .= ' AND itemID IN (' . implode(',', array_fill(0, sizeOf($itemIDs), '?')) . ')'; } $stmt = Zotero_DB::getStatement($sql, "loadItems_" . sizeOf($itemIDs), $shardID); $itemRows = Zotero_DB::queryFromStatement($stmt, $itemIDs); $loadedItemIDs = array(); if ($itemRows) { foreach ($itemRows as $row) { if ($row['libraryID'] != $libraryID) { throw new Exception("Item {$itemID} isn't in library {$libraryID}", Z_ERROR_OBJECT_LIBRARY_MISMATCH); } $itemID = $row['id']; $loadedItemIDs[] = $itemID; // Item isn't loaded -- create new object and stuff in array if (!isset(self::$objectCache[$itemID])) { $item = new Zotero_Item(); $item->loadFromRow($row, true); self::$objectCache[$itemID] = $item; } else { self::$objectCache[$itemID]->loadFromRow($row, true); } } } if (!$itemIDs) { // If loading all items, remove old items that no longer exist $ids = array_keys(self::$objectCache); foreach ($ids as $id) { if (!in_array($id, $loadedItemIDs)) { throw new Exception("Unimplemented"); //$this->unload($id); } } } }
public function testNumAttachments() { $item = new Zotero_Item(); $item->libraryID = self::$config['userLibraryID']; $item->itemTypeID = Zotero_ItemTypes::getID("book"); $item->save(); $this->assertEquals(0, $item->numAttachments()); $attachmentItem = new Zotero_Item(); $attachmentItem->libraryID = self::$config['userLibraryID']; $attachmentItem->itemTypeID = Zotero_ItemTypes::getID("attachment"); $attachmentItem->setSource($item->id); $attachmentItem->save(); $this->assertEquals(1, $item->numAttachments()); }
/** * Put an item in the trash * * @param Zotero_Item $item * @return Zotero_Response */ public function trashItem($item) { $item->set('deleted', 1); $this->writeUpdatedItem($item); }
private static function loadItems($libraryID, $itemIDs = array()) { $shardID = Zotero_Shards::getByLibraryID($libraryID); $sql = 'SELECT I.*, (SELECT COUNT(*) FROM itemNotes INo WHERE sourceItemID=I.itemID AND INo.itemID NOT IN (SELECT itemID FROM deletedItems)) AS numNotes, (SELECT COUNT(*) FROM itemAttachments IA WHERE sourceItemID=I.itemID AND IA.itemID NOT IN (SELECT itemID FROM deletedItems)) AS numAttachments FROM items I WHERE 1'; // TODO: optimize if ($itemIDs) { foreach ($itemIDs as $itemID) { if (!is_int($itemID)) { throw new Exception("Invalid itemID {$itemID}"); } } $sql .= ' AND I.itemID IN (' . implode(',', array_fill(0, sizeOf($itemIDs), '?')) . ')'; } $stmt = Zotero_DB::getStatement($sql, "loadItems_" . sizeOf($itemIDs), $shardID); $itemRows = Zotero_DB::queryFromStatement($stmt, $itemIDs); $loadedItemIDs = array(); if ($itemRows) { foreach ($itemRows as $row) { if ($row['libraryID'] != $libraryID) { throw new Exception("Item {$itemID} isn't in library {$libraryID}", Z_ERROR_OBJECT_LIBRARY_MISMATCH); } $itemID = $row['itemID']; $loadedItemIDs[] = $itemID; // Item isn't loaded -- create new object and stuff in array if (!isset(self::$itemsByID[$itemID])) { $item = new Zotero_Item(); $item->loadFromRow($row, true); self::$itemsByID[$itemID] = $item; } else { self::$itemsByID[$itemID]->loadFromRow($row, true); } } } if (!$itemIDs) { // If loading all items, remove old items that no longer exist $ids = array_keys(self::$itemsByID); foreach ($ids as $id) { if (!in_array($id, $loadedItemIDs)) { throw new Exception("Unimplemented"); //$this->unload($id); } } /* _cachedFields = ['itemID', 'itemTypeID', 'dateAdded', 'dateModified', 'numNotes', 'numAttachments', 'numChildren']; */ //this._reloadCache = false; } }
/** * Put an item in the trash * * @param Zotero_Item $item * @return Zotero_Response */ public function trashItem($item) { return $item->trashItem(); }
public function testCollectionAndTags() { $templateJsonString = <<<'EOD' {"itemType":"journalArticle","title":"","creators":[{"creatorType":"author","firstName":"","lastName":""}],"abstractNote":"","publicationTitle":"","volume":"","issue":"","pages":"","date":"","series":"","seriesTitle":"","seriesText":"","journalAbbreviation":"","language":"","DOI":"","ISSN":"","shortTitle":"","url":"","accessDate":"","archive":"","archiveLocation":"","libraryCatalog":"","callNumber":"","rights":"","extra":"","tags":[],"collections":[],"relations":{}} EOD; $templateArray = json_decode($templateJsonString, true); $item = new Zotero_Item(); $item->initItemFromTemplate($templateArray); $item->addToCollection("ASDF1234"); $item->addToCollection("FDSA4321"); $item->addTag("Green"); $item->addTag("purple", 1); $item->addTag("Red"); $itemCollections = $item->get('collections'); $this->assertEquals(count($itemCollections), 2, 'right number of collections'); $this->assertEquals($itemCollections[0], "ASDF1234", "first col match"); $this->assertEquals($itemCollections[1], "FDSA4321", "Second col match"); $itemTags = $item->get('tags'); $this->assertEquals(count($itemTags), 3); $this->assertEquals($itemTags[0], "Green"); $this->assertEquals($itemTags[1]['tag'], "purple"); $this->assertEquals($itemTags[1]['type'], 1); $this->assertEquals($itemTags[2], "Red"); //test removal $item->removeFromCollection('OIUSDGAS'); $item->removeFromCollection("ASDF1234"); $item->removeTag("Red"); $item->removeTag("Green"); $itemCollections = $item->get('collections'); $this->assertEquals(count($itemCollections), 1, 'right number of collections'); $this->assertEquals($itemCollections[0], "FDSA4321", "first col match"); $itemTags = $item->get('tags'); $this->assertEquals(count($itemTags), 1); $this->assertEquals($itemTags[0]['tag'], "purple"); $this->assertEquals($itemTags[0]['type'], 1); }