Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions controllers/StorageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,67 @@ public function storagetransferbucket() {
Zotero_Storage::transferBucket('zoterofilestorage', 'zoterofilestoragetest');
exit;
}

public function identify() {
$this->allowMethods(array('POST'));

// 10 requests per second per IP with 100 requests burst
$rateLimit = [
'logOnly' => false,
'bucket' => $_SERVER['REMOTE_ADDR'],
'capacity' => 100,
'rate' => 10
];

// $this->requestLimiter must be initialized in ApiController
$requestsRemaining = $this->requestLimiter->checkBucketRate($rateLimit);

if (!$requestsRemaining) {
StatsD::increment("request.limit.identify.rate.rejected", 1);
Z_Core::logError('Request rate limit exceeded for' . $rateLimit['bucket']);

if (!$rateLimit['logOnly']) {
header("Retry-After: " . (int)$rateLimit['capacity'] / $rateLimit['rate']);
$this->e429();
}
}

if (!empty($_REQUEST['hash'])) {
$hash = $_REQUEST['hash'];
$fieldTypes = [
11, // ISBN
13, // ISSN
26 // DOI
];
$identifiers = [];

// Returns up to 10 identifiers and checks up to 5 libraries
$numIdentifiers = 0;
$numLibraries = 0;

$libraryIDs = Zotero_Storage::getHashLibraries($hash);
while (($libraryID = array_shift($libraryIDs))
&& $numIdentifiers < 10
&& $numLibraries++ < 5) {
$fields = Zotero_Storage::getFileSourceFields($libraryID, $hash, $fieldTypes);
foreach ($fields as $fieldID => $values) {
$fieldName = Zotero_ItemFields::getName($fieldID);
foreach ($values as $value) {
if (!isset($identifiers[$fieldName])) {
$identifiers[$fieldName] = [];
}

if (!in_array($value, $identifiers[$fieldName])) {
$identifiers[$fieldName][] = $value;
$numIdentifiers++;
}
}
}
}

echo Zotero_Utilities::formatJSON([
'identifiers' => $identifiers
]);
}
}
}
1 change: 1 addition & 0 deletions include/config/routes.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
$router->map('/users/i:objectUserID/publications/items/:objectKey/file/view', ['controller' => 'Items', 'extra' => ['allowHTTP' => true, 'file' => true, 'view' => true, 'publications' => true]]);
$router->map('/groups/i:objectGroupID/items/:objectKey/file', array('controller' => 'Items', 'extra' => array('allowHTTP' => true, 'file' => true)));
$router->map('/groups/i:objectGroupID/items/:objectKey/file/view', array('controller' => 'Items', 'extra' => array('allowHTTP' => true, 'file' => true, 'view' => true)));
$router->map('/identify', array('controller' => 'Storage', 'action' => 'identify'));

// Full-text content
$router->map('/users/i:objectUserID/items/:objectKey/fulltext', array('controller' => 'FullText', 'action' => 'itemContent'));
Expand Down
24 changes: 24 additions & 0 deletions model/Storage.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,30 @@ public static function getUserUsage($userID) {
return $usage;
}

public static function getHashLibraries($hash) {
$sql = "SELECT libraryID FROM storageFiles JOIN storageFileLibraries USING (storageFileID) WHERE hash = ?";
return Zotero_DB::columnQuery($sql, $hash);
}

public static function getFileSourceFields($libraryID, $hash, $fieldTypes) {
// Limit sourceItem metadata fields per library, to give a chance
// for other libraries to impact result in case if
// one library has incorrect metadata.
// Only non-empty fields exist in itemData
$sql = "SELECT fieldID, `value` FROM itemData WHERE itemID IN
(SELECT sourceItemID FROM itemAttachments
JOIN items USING (itemID) WHERE libraryID = ? AND storageHash = ?)
AND fieldID IN (" . implode(',', $fieldTypes) . ") LIMIT 2";
$rows = Zotero_DB::query($sql, array($libraryID, $hash), Zotero_Shards::getByLibraryID($libraryID));
$fields = [];
foreach ($rows as $row) {
if (!isset($fields[$row['fieldID']])) {
$fields[$row['fieldID']] = [];
}
$fields[$row['fieldID']][] = $row['value'];
}
return $fields;
}

private static function updateLastAdded($storageFileID) {
$sql = "UPDATE storageFiles SET lastAdded=NOW() WHERE storageFileID=?";
Expand Down