Beispiel #1
0
 public function run($id = null)
 {
     $this->id = $id;
     $this->addr = gethostbyname(gethostname());
     if (!Z_CONFIG::$PROCESSORS_ENABLED) {
         $sleep = 20;
         $this->log("Processors disabled — exiting in {$sleep} seconds");
         sleep($sleep);
         try {
             $this->notifyProcessor("LOCK" . " " . $id);
         } catch (Exception $e) {
             $this->log($e);
         }
         return;
     }
     $this->log("Starting sync processor");
     $startTime = microtime(true);
     try {
         $processed = $this->processFromQueue();
         if (Zotero_DB::transactionInProgress()) {
             error_log("WARNING: Transaction still in progress after processing!");
         }
     } catch (Exception $e) {
         $this->log($e);
         throw $e;
     }
     $duration = microtime(true) - $startTime;
     $error = false;
     // Success
     if ($processed == 1) {
         $this->log("Process completed in " . round($duration, 2) . " seconds");
         $signal = "DONE";
     } else {
         if ($processed == 0) {
             $this->log("Exiting with no processes found");
             $signal = "NONE";
         } else {
             if ($processed == -1) {
                 $this->log("Exiting on lock error");
                 $signal = "LOCK";
             } else {
                 $this->log("Exiting on error");
                 $signal = "ERROR";
             }
         }
     }
     if ($id) {
         try {
             $this->notifyProcessor($signal . " " . $id);
         } catch (Exception $e) {
             $this->log($e);
         }
     }
 }
Beispiel #2
0
 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();
 }
Beispiel #3
0
 public static function updateFromJSON(Zotero_Item $item, $json, Zotero_Item $parentItem = null, $requestParams, $userID, $requireVersion = 0, $partialUpdate = false)
 {
     $json = Zotero_API::extractEditableJSON($json);
     $exists = Zotero_API::processJSONObjectKey($item, $json, $requestParams);
     // computerProgram used 'version' instead of 'versionNumber' before v3
     if ($requestParams['v'] < 3 && isset($json->version)) {
         $json->versionNumber = $json->version;
         unset($json->version);
     }
     Zotero_API::checkJSONObjectVersion($item, $json, $requestParams, $requireVersion);
     self::validateJSONItem($json, $item->libraryID, $exists ? $item : null, $parentItem || ($exists ? !!$item->getSourceKey() : false), $requestParams, $partialUpdate && $exists);
     $changed = false;
     $twoStage = false;
     if (!Zotero_DB::transactionInProgress()) {
         Zotero_DB::beginTransaction();
         $transactionStarted = true;
     } else {
         $transactionStarted = false;
     }
     // Set itemType first
     if (isset($json->itemType)) {
         $item->setField("itemTypeID", Zotero_ItemTypes::getID($json->itemType));
     }
     $changedDateModified = false;
     foreach ($json as $key => $val) {
         switch ($key) {
             case 'key':
             case 'version':
             case 'itemKey':
             case 'itemVersion':
             case 'itemType':
             case 'deleted':
                 continue;
             case 'parentItem':
                 $item->setSourceKey($val);
                 break;
             case 'creators':
                 if (!$val && !$item->numCreators()) {
                     continue 2;
                 }
                 $orderIndex = -1;
                 foreach ($val as $newCreatorData) {
                     // JSON uses 'name' and 'firstName'/'lastName',
                     // so switch to just 'firstName'/'lastName'
                     if (isset($newCreatorData->name)) {
                         $newCreatorData->firstName = '';
                         $newCreatorData->lastName = $newCreatorData->name;
                         unset($newCreatorData->name);
                         $newCreatorData->fieldMode = 1;
                     } else {
                         $newCreatorData->fieldMode = 0;
                     }
                     // Skip empty creators
                     if (Zotero_Utilities::unicodeTrim($newCreatorData->firstName) === "" && Zotero_Utilities::unicodeTrim($newCreatorData->lastName) === "") {
                         break;
                     }
                     $orderIndex++;
                     $newCreatorTypeID = Zotero_CreatorTypes::getID($newCreatorData->creatorType);
                     // Same creator in this position
                     $existingCreator = $item->getCreator($orderIndex);
                     if ($existingCreator && $existingCreator['ref']->equals($newCreatorData)) {
                         // Just change the creatorTypeID
                         if ($existingCreator['creatorTypeID'] != $newCreatorTypeID) {
                             $item->setCreator($orderIndex, $existingCreator['ref'], $newCreatorTypeID);
                         }
                         continue;
                     }
                     // Same creator in a different position, so use that
                     $existingCreators = $item->getCreators();
                     for ($i = 0, $len = sizeOf($existingCreators); $i < $len; $i++) {
                         if ($existingCreators[$i]['ref']->equals($newCreatorData)) {
                             $item->setCreator($orderIndex, $existingCreators[$i]['ref'], $newCreatorTypeID);
                             continue;
                         }
                     }
                     // Make a fake creator to use for the data lookup
                     $newCreator = new Zotero_Creator();
                     $newCreator->libraryID = $item->libraryID;
                     foreach ($newCreatorData as $key => $val) {
                         if ($key == 'creatorType') {
                             continue;
                         }
                         $newCreator->{$key} = $val;
                     }
                     // Look for an equivalent creator in this library
                     $candidates = Zotero_Creators::getCreatorsWithData($item->libraryID, $newCreator, true);
                     if ($candidates) {
                         $c = Zotero_Creators::get($item->libraryID, $candidates[0]);
                         $item->setCreator($orderIndex, $c, $newCreatorTypeID);
                         continue;
                     }
                     // None found, so make a new one
                     $creatorID = $newCreator->save();
                     $newCreator = Zotero_Creators::get($item->libraryID, $creatorID);
                     $item->setCreator($orderIndex, $newCreator, $newCreatorTypeID);
                 }
                 // Remove all existing creators above the current index
                 if ($exists && ($indexes = array_keys($item->getCreators()))) {
                     $i = max($indexes);
                     while ($i > $orderIndex) {
                         $item->removeCreator($i);
                         $i--;
                     }
                 }
                 break;
             case 'tags':
                 $item->setTags($val);
                 break;
             case 'collections':
                 $item->setCollections($val);
                 break;
             case 'relations':
                 $item->setRelations($val);
                 break;
             case 'attachments':
             case 'notes':
                 if (!$val) {
                     continue;
                 }
                 $twoStage = true;
                 break;
             case 'note':
                 $item->setNote($val);
                 break;
                 // Attachment properties
             // Attachment properties
             case 'linkMode':
                 $item->attachmentLinkMode = Zotero_Attachments::linkModeNameToNumber($val, true);
                 break;
             case 'contentType':
             case 'charset':
             case 'filename':
                 $k = "attachment" . ucwords($key);
                 $item->{$k} = $val;
                 break;
             case 'md5':
                 $item->attachmentStorageHash = $val;
                 break;
             case 'mtime':
                 $item->attachmentStorageModTime = $val;
                 break;
             case 'dateModified':
                 $changedDateModified = $item->setField($key, $val);
                 break;
             default:
                 $item->setField($key, $val);
                 break;
         }
     }
     if ($parentItem) {
         $item->setSource($parentItem->id);
     } else {
         if ($requestParams['v'] >= 2 && !$partialUpdate && $item->getSourceKey() && !isset($json->parentItem)) {
             $item->setSourceKey(false);
         }
     }
     $item->deleted = !empty($json->deleted);
     // If item has changed, update it with the current timestamp
     if ($item->hasChanged() && !$changedDateModified) {
         $item->dateModified = Zotero_DB::getTransactionTimestamp();
     }
     $changed = $item->save($userID) || $changed;
     // Additional steps that have to be performed on a saved object
     if ($twoStage) {
         foreach ($json as $key => $val) {
             switch ($key) {
                 case 'attachments':
                     if (!$val) {
                         continue;
                     }
                     foreach ($val as $attachmentJSON) {
                         $childItem = new Zotero_Item();
                         $childItem->libraryID = $item->libraryID;
                         self::updateFromJSON($childItem, $attachmentJSON, $item, $requestParams, $userID);
                     }
                     break;
                 case 'notes':
                     if (!$val) {
                         continue;
                     }
                     $noteItemTypeID = Zotero_ItemTypes::getID("note");
                     foreach ($val as $note) {
                         $childItem = new Zotero_Item();
                         $childItem->libraryID = $item->libraryID;
                         $childItem->itemTypeID = $noteItemTypeID;
                         $childItem->setSource($item->id);
                         $childItem->setNote($note->note);
                         $childItem->save();
                     }
                     break;
             }
         }
     }
     if ($transactionStarted) {
         Zotero_DB::commit();
     }
     return $changed;
 }
Beispiel #4
0
 public static function updateMultipleFromJSON($json, $requestParams, $libraryID, $userID, Zotero_Permissions $permissions, $requireVersion, $parent = null)
 {
     $type = self::$objectType;
     $types = self::$objectTypePlural;
     $keyProp = $type . "Key";
     switch ($type) {
         case 'collection':
         case 'search':
             if ($parent) {
                 throw new Exception('$parent is not valid for ' . $type);
             }
             break;
         case 'item':
             break;
         default:
             throw new Exception("Function not valid for {$type}");
     }
     self::validateMultiObjectJSON($json, $requestParams);
     $results = new Zotero_Results($requestParams);
     if ($requestParams['v'] >= 2 && Zotero_DB::transactionInProgress()) {
         throw new Exception("Transaction cannot be open when starting multi-object update");
     }
     // If single collection object, stuff in array
     if ($requestParams['v'] < 2 && $type == 'collection' && !isset($json->collections)) {
         $json = [$json];
     } else {
         if ($requestParams['v'] < 3) {
             $json = $json->{$types};
         }
     }
     $i = 0;
     foreach ($json as $prop => $jsonObject) {
         Zotero_DB::beginTransaction();
         try {
             if (!is_object($jsonObject)) {
                 throw new Exception("Invalid value for index {$prop} in uploaded data; expected JSON {$type} object", Z_ERROR_INVALID_INPUT);
             }
             $className = "Zotero_" . ucwords($type);
             $obj = new $className();
             $obj->libraryID = $libraryID;
             if ($type == 'item') {
                 $changed = self::updateFromJSON($obj, $jsonObject, $parent, $requestParams, $userID, $requireVersion, true);
             } else {
                 $changed = self::updateFromJSON($obj, $jsonObject, $requestParams, $userID, $requireVersion, true);
             }
             Zotero_DB::commit();
             if ($changed) {
                 $results->addSuccessful($i, $obj->toResponseJSON($requestParams, $permissions));
             } else {
                 $results->addUnchanged($i, $obj->key);
             }
         } catch (Exception $e) {
             Zotero_DB::rollback();
             if ($requestParams['v'] < 2) {
                 throw $e;
             }
             // If object key given, include that
             $resultKey = isset($jsonObject->{$keyProp}) ? $jsonObject->{$keyProp} : '';
             $results->addFailure($i, $resultKey, $e);
         }
         $i++;
     }
     return $results->generateReport();
 }
Beispiel #5
0
 public function checkDBTransactionState()
 {
     if (Zotero_DB::transactionInProgress()) {
         error_log("Transaction still in progress at request end! " . "[" . $this->method . " " . $_SERVER['REQUEST_URI'] . "]");
     }
 }
Beispiel #6
0
 /**
  * @param Zotero_Collection $collection The collection object to update;
  *                                      this should be either an existing
  *                                      collection or a new collection
  *                                      with a library assigned.
  * @param object $json Collection data to write
  * @param boolean [$requireVersion=0] See Zotero_API::checkJSONObjectVersion()
  * @return boolean True if the collection was changed, false otherwise
  */
 public static function updateFromJSON(Zotero_Collection $collection, $json, $requestParams, $userID, $requireVersion = 0, $partialUpdate = false)
 {
     $json = Zotero_API::extractEditableJSON($json);
     $exists = Zotero_API::processJSONObjectKey($collection, $json, $requestParams);
     Zotero_API::checkJSONObjectVersion($collection, $json, $requestParams, $requireVersion);
     self::validateJSONCollection($json, $requestParams, $partialUpdate && $exists);
     $changed = false;
     if (!Zotero_DB::transactionInProgress()) {
         Zotero_DB::beginTransaction();
         $transactionStarted = true;
     } else {
         $transactionStarted = false;
     }
     if (isset($json->name)) {
         $collection->name = $json->name;
     }
     if ($requestParams['v'] >= 2 && isset($json->parentCollection)) {
         $collection->parentKey = $json->parentCollection;
     } else {
         if ($requestParams['v'] < 2 && isset($json->parent)) {
             $collection->parentKey = $json->parent;
         } else {
             if (!$partialUpdate) {
                 $collection->parent = false;
             }
         }
     }
     $changed = $collection->save() || $changed;
     if ($requestParams['v'] >= 2) {
         if (isset($json->relations)) {
             $changed = $collection->setRelations($json->relations, $userID) || $changed;
         } else {
             if (!$partialUpdate) {
                 $changed = $collection->setRelations(new stdClass(), $userID) || $changed;
             }
         }
     }
     if ($transactionStarted) {
         Zotero_DB::commit();
     }
     return $changed;
 }
Beispiel #7
0
 /**
  * @param Zotero_Setting $setting The setting object to update;
  *                                this should be either an existing
  *                                setting or a new setting
  *                                with a library and name assigned.
  * @param object $json Setting data to write
  * @param boolean [$requireVersion=0] See Zotero_API::checkJSONObjectVersion()
  * @return boolean True if the setting was changed, false otherwise
  */
 public static function updateFromJSON(Zotero_Setting $setting, $json, $requestParams, $userID, $requireVersion = 0)
 {
     self::validateJSONObject($setting->name, $json, $requestParams);
     Zotero_API::checkJSONObjectVersion($setting, $json, $requestParams, $requireVersion);
     $changed = false;
     if (!Zotero_DB::transactionInProgress()) {
         Zotero_DB::beginTransaction();
         $transactionStarted = true;
     } else {
         $transactionStarted = false;
     }
     $setting->value = $json->value;
     $changed = $setting->save() || $changed;
     if ($transactionStarted) {
         Zotero_DB::commit();
     }
     return $changed;
 }