Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File identifier #57

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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