Ejemplo n.º 1
0
 public function keys()
 {
     $userID = $this->objectUserID;
     $key = $this->objectName;
     $this->allowMethods(['GET', 'POST', 'PUT', 'DELETE']);
     if ($this->method == 'GET') {
         // Single key
         if ($key) {
             $keyObj = Zotero_Keys::getByKey($key);
             if (!$keyObj) {
                 $this->e404("Key not found");
             }
             // /users/<userID>/keys/<keyID> (deprecated)
             if ($userID) {
                 // If we have a userID, make sure it matches
                 if ($keyObj->userID != $userID) {
                     $this->e404("Key not found");
                 }
             } else {
                 if ($this->apiVersion < 3) {
                     $this->e404();
                 }
             }
             if ($this->apiVersion >= 3) {
                 $json = $keyObj->toJSON();
                 // If not super-user, don't include name or recent IP addresses
                 if (!$this->permissions->isSuper()) {
                     unset($json['dateAdded']);
                     unset($json['lastUsed']);
                     unset($json['name']);
                     unset($json['recentIPs']);
                 }
                 header('application/json');
                 echo Zotero_Utilities::formatJSON($json);
             } else {
                 $this->responseXML = $keyObj->toXML();
                 // If not super-user, don't include name or recent IP addresses
                 if (!$this->permissions->isSuper()) {
                     unset($this->responseXML['dateAdded']);
                     unset($this->responseXML['lastUsed']);
                     unset($this->responseXML->name);
                     unset($this->responseXML->recentIPs);
                 }
             }
         } else {
             if (!$this->permissions->isSuper()) {
                 $this->e403();
             }
             $keyObjs = Zotero_Keys::getUserKeys($userID);
             if ($keyObjs) {
                 if ($this->apiVersion >= 3) {
                     $json = [];
                     foreach ($keyObjs as $keyObj) {
                         $json[] = $keyObj->toJSON();
                     }
                     echo Zotero_Utilities::formatJSON($json);
                 } else {
                     $xml = new SimpleXMLElement('<keys/>');
                     $domXML = dom_import_simplexml($xml);
                     foreach ($keyObjs as $keyObj) {
                         $keyXML = $keyObj->toXML();
                         $domKeyXML = dom_import_simplexml($keyXML);
                         $node = $domXML->ownerDocument->importNode($domKeyXML, true);
                         $domXML->appendChild($node);
                     }
                     $this->responseXML = $xml;
                 }
             }
         }
     } else {
         if ($this->method == 'DELETE') {
             if (!$key) {
                 $this->e400("DELETE requests must end with a key");
             }
             Zotero_DB::beginTransaction();
             $keyObj = Zotero_Keys::getByKey($key);
             if (!$keyObj) {
                 $this->e404("Key '{$key}' does not exist");
             }
             $keyObj->erase();
             Zotero_DB::commit();
             header("HTTP/1.1 204 No Content");
             exit;
         } else {
             // Require super-user for modifications
             if (!$this->permissions->isSuper()) {
                 $this->e403();
             }
             if ($this->method == 'POST') {
                 if ($key) {
                     $this->e400("POST requests cannot end with a key (did you mean PUT?)");
                 }
                 if ($this->apiVersion >= 3) {
                     $json = json_decode($this->body, true);
                     if (!$json) {
                         $this->e400("{$this->method} data is not valid JSON");
                     }
                     if (!empty($json['key'])) {
                         $this->e400("POST requests cannot contain a key in '" . $this->body . "'");
                     }
                     $fields = $this->getFieldsFromJSON($json);
                 } else {
                     try {
                         $keyXML = @new SimpleXMLElement($this->body);
                     } catch (Exception $e) {
                         $this->e400("{$this->method} data is not valid XML");
                     }
                     if (!empty($key['key'])) {
                         $this->e400("POST requests cannot contain a key in '" . $this->body . "'");
                     }
                     $fields = $this->getFieldsFromKeyXML($keyXML);
                 }
                 Zotero_DB::beginTransaction();
                 try {
                     $keyObj = new Zotero_Key();
                     $keyObj->userID = $userID;
                     foreach ($fields as $field => $val) {
                         if ($field == 'access') {
                             foreach ($val as $access) {
                                 $this->setKeyPermissions($keyObj, $access);
                             }
                         } else {
                             $keyObj->{$field} = $val;
                         }
                     }
                     $keyObj->save();
                 } catch (Exception $e) {
                     if ($e->getCode() == Z_ERROR_KEY_NAME_TOO_LONG) {
                         $this->e400($e->getMessage());
                     }
                     $this->handleException($e);
                 }
                 if ($this->apiVersion >= 3) {
                     header('application/json');
                     echo Zotero_Utilities::formatJSON($keyObj->toJSON());
                 } else {
                     $this->responseXML = $keyObj->toXML();
                 }
                 Zotero_DB::commit();
                 $url = Zotero_API::getKeyURI($keyObj);
                 $this->responseCode = 201;
                 header("Location: " . $url, false, 201);
             } else {
                 if ($this->method == 'PUT') {
                     if (!$key) {
                         $this->e400("PUT requests must end with a key (did you mean POST?)");
                     }
                     if ($this->apiVersion >= 3) {
                         $json = json_decode($this->body, true);
                         if (!$json) {
                             $this->e400("{$this->method} data is not valid JSON");
                         }
                         $fields = $this->getFieldsFromJSON($json);
                     } else {
                         try {
                             $keyXML = @new SimpleXMLElement($this->body);
                         } catch (Exception $e) {
                             $this->e400("{$this->method} data is not valid XML");
                         }
                         $fields = $this->getFieldsFromKeyXML($keyXML);
                     }
                     // Key attribute is optional, but, if it's there, make sure it matches
                     if (isset($fields['key']) && $fields['key'] != $key) {
                         $this->e400("Key '{$fields['key']}' does not match key '{$key}' from URI");
                     }
                     Zotero_DB::beginTransaction();
                     try {
                         $keyObj = Zotero_Keys::getByKey($key);
                         if (!$keyObj) {
                             $this->e404("Key '{$key}' does not exist");
                         }
                         foreach ($fields as $field => $val) {
                             if ($field == 'access') {
                                 foreach ($val as $access) {
                                     $this->setKeyPermissions($keyObj, $access);
                                 }
                             } else {
                                 $keyObj->{$field} = $val;
                             }
                         }
                         $keyObj->save();
                     } catch (Exception $e) {
                         if ($e->getCode() == Z_ERROR_KEY_NAME_TOO_LONG) {
                             $this->e400($e->getMessage());
                         }
                         $this->handleException($e);
                     }
                     if ($this->apiVersion >= 3) {
                         echo Zotero_Utilities::formatJSON($keyObj->toJSON());
                     } else {
                         $this->responseXML = $keyObj->toXML();
                     }
                     Zotero_DB::commit();
                 }
             }
         }
     }
     if ($this->apiVersion >= 3) {
         $this->end();
     } else {
         header('Content-Type: application/xml');
         $xmlstr = $this->responseXML->asXML();
         $doc = new DOMDocument('1.0');
         $doc->loadXML($xmlstr);
         $doc->formatOutput = true;
         echo $doc->saveXML();
         exit;
     }
 }
Ejemplo n.º 2
0
 /**
  * Used for integration tests
  *
  * Valid only on testing site
  */
 public function testSetup()
 {
     if (!$this->permissions->isSuper()) {
         $this->e404();
     }
     if (!Z_ENV_TESTING_SITE) {
         $this->e404();
     }
     $this->allowMethods(['POST']);
     if (empty($_GET['u'])) {
         throw new Exception("User not provided (e.g., ?u=1)");
     }
     $userID = $_GET['u'];
     // Clear keys
     $keys = Zotero_Keys::getUserKeys($userID);
     foreach ($keys as $keyObj) {
         $keyObj->erase();
     }
     $keys = Zotero_Keys::getUserKeys($userID);
     if ($keys) {
         throw new Exception("Keys still exist");
     }
     // Create new key
     $keyObj = new Zotero_Key();
     $keyObj->userID = $userID;
     $keyObj->name = "Tests Key";
     $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     $keyObj->setPermission($libraryID, 'library', true);
     $keyObj->setPermission($libraryID, 'notes', true);
     $keyObj->setPermission($libraryID, 'write', true);
     $keyObj->setPermission(0, 'group', true);
     $keyObj->setPermission(0, 'write', true);
     $keyObj->save();
     $key = $keyObj->key;
     Zotero_DB::beginTransaction();
     // Clear data
     Zotero_Users::clearAllData($userID);
     // Delete publications library, so we can test auto-creating it
     $publicationsLibraryID = Zotero_Users::getLibraryIDFromUserID($userID, 'publications');
     if ($publicationsLibraryID) {
         // Delete user publications shard library
         $sql = "DELETE FROM shardLibraries WHERE libraryID=?";
         Zotero_DB::query($sql, $publicationsLibraryID, Zotero_Shards::getByUserID($userID));
         // Delete user publications library
         $sql = "DELETE FROM libraries WHERE libraryID=?";
         Zotero_DB::query($sql, $publicationsLibraryID);
         Z_Core::$MC->delete('userPublicationsLibraryID_' . $userID);
         Z_Core::$MC->delete('libraryUserID_' . $publicationsLibraryID);
     }
     Zotero_DB::commit();
     echo json_encode(["apiKey" => $key]);
     $this->end();
 }
Ejemplo n.º 3
0
 /**
  * Used for integration tests
  *
  * Valid only on testing site
  */
 public function testSetup()
 {
     if (!$this->permissions->isSuper()) {
         $this->e404();
     }
     if (!Z_ENV_TESTING_SITE) {
         $this->e404();
     }
     if (empty($_GET['u'])) {
         throw new Exception("User not provided (e.g., ?u=1)");
     }
     $userID = $_GET['u'];
     // Clear keys
     $keys = Zotero_Keys::getUserKeys($userID);
     foreach ($keys as $keyObj) {
         $keyObj->erase();
     }
     $keys = Zotero_Keys::getUserKeys($userID);
     if ($keys) {
         throw new Exception("Keys still exist");
     }
     // Clear data
     Zotero_Users::clearAllData($userID);
     $this->responseXML = new SimpleXMLElement("<ok/>");
     $this->end();
 }
Ejemplo n.º 4
0
 public function save()
 {
     if (!$this->loaded) {
         Z_Core::debug("Not saving unloaded group {$this->id}");
         return;
     }
     if (empty($this->changed)) {
         Z_Core::debug("Group {$this->id} has not changed", 4);
         return;
     }
     if (!$this->ownerUserID) {
         throw new Exception("Cannot save group without owner");
     }
     if (!$this->name) {
         throw new Exception("Cannot save group without name");
     }
     if (mb_strlen($this->description) > 1024) {
         throw new Exception("Group description too long", Z_ERROR_GROUP_DESCRIPTION_TOO_LONG);
     }
     Zotero_DB::beginTransaction();
     $libraryID = $this->libraryID;
     if (!$libraryID) {
         $shardID = Zotero_Shards::getNextShard();
         $libraryID = Zotero_Libraries::add('group', $shardID);
         if (!$libraryID) {
             throw new Exception('libraryID not available after Zotero_Libraries::add()');
         }
     }
     $fields = array('name', 'slug', 'type', 'description', 'url', 'hasImage');
     if ($this->isPublic()) {
         $existing = Zotero_Groups::publicNameExists($this->name);
         if ($existing && $existing != $this->id) {
             throw new Exception("Public group with name '{$this->name}' already exists", Z_ERROR_PUBLIC_GROUP_EXISTS);
         }
     }
     $fields = array_merge($fields, array('libraryEditing', 'libraryReading', 'fileEditing'));
     $sql = "INSERT INTO groups\n\t\t\t\t\t(groupID, libraryID, " . implode(", ", $fields) . ", dateModified)\n\t\t\t\t\tVALUES (?, ?, " . implode(", ", array_fill(0, sizeOf($fields), "?")) . ", CURRENT_TIMESTAMP)";
     $params = array($this->id, $libraryID);
     foreach ($fields as $field) {
         if (is_bool($this->{$field})) {
             $params[] = (int) $this->{$field};
         } else {
             $params[] = $this->{$field};
         }
     }
     $sql .= " ON DUPLICATE KEY UPDATE ";
     $q = array();
     foreach ($fields as $field) {
         $q[] = "{$field}=?";
         if (is_bool($this->{$field})) {
             $params[] = (int) $this->{$field};
         } else {
             $params[] = $this->{$field};
         }
     }
     $sql .= implode(", ", $q) . ", " . "dateModified=CURRENT_TIMESTAMP, " . "version=IF(version = 255, 1, version + 1)";
     $insertID = Zotero_DB::query($sql, $params);
     if (!$this->id) {
         if (!$insertID) {
             throw new Exception("Group id not available after INSERT");
         }
         $this->id = $insertID;
     }
     if (!$this->libraryID) {
         $this->libraryID = $libraryID;
     }
     // If creating group or changing owner
     if (!empty($this->changed['ownerUserID'])) {
         $sql = "SELECT userID FROM groupUsers WHERE groupID=? AND role='owner'";
         $currentOwner = Zotero_DB::valueQuery($sql, $this->id);
         $newOwner = $this->ownerUserID;
         // Move existing owner out of the way, if there is one
         if ($currentOwner) {
             $sql = "UPDATE groupUsers SET role='admin' WHERE groupID=? AND userID=?";
             Zotero_DB::query($sql, array($this->id, $currentOwner));
         }
         // Make sure new owner exists in DB
         if (!Zotero_Users::exists($newOwner)) {
             Zotero_Users::addFromWWW($newOwner);
         }
         // Add new owner to group
         $sql = "INSERT INTO groupUsers (groupID, userID, role, joined) VALUES\n\t\t\t\t\t(?, ?, 'owner', CURRENT_TIMESTAMP) ON DUPLICATE KEY UPDATE\n\t\t\t\t\trole='owner', lastUpdated=CURRENT_TIMESTAMP";
         Zotero_DB::query($sql, array($this->id, $newOwner));
         // Delete any record of this user losing access to the group
         $libraryID = Zotero_Users::getLibraryIDFromUserID($this->ownerUserID);
         $sql = "DELETE FROM syncDeleteLogIDs WHERE libraryID=? AND objectType='group' AND id=?";
         Zotero_DB::query($sql, array($libraryID, $this->id), Zotero_Shards::getByLibraryID($this->libraryID));
         // Send library removal notification for all API keys belonging to the former owner
         // with access to this group
         $apiKeys = Zotero_Keys::getUserKeysWithLibrary($currentOwner, $this->libraryID);
         Zotero_Notifier::trigger('remove', 'apikey-library', array_map(function ($key) {
             return $key->key . "-" . $this->libraryID;
         }, $apiKeys));
         // Send library add notification for all API keys belonging to the new owner
         // with access to this group
         $apiKeys = Zotero_Keys::getUserKeysWithLibrary($newOwner, $this->libraryID);
         Zotero_Notifier::trigger('add', 'apikey-library', array_map(function ($key) {
             return $key->key . "-" . $this->libraryID;
         }, $apiKeys));
     }
     // If any of the group's users have a queued upload, flag group for a timestamp
     // update once the sync is done so that the uploading user gets the change
     try {
         $userIDs = self::getUsers();
         foreach ($userIDs as $userID) {
             if ($syncUploadQueueID = Zotero_Sync::getUploadQueueIDByUserID($userID)) {
                 Zotero_Sync::postWriteLog($syncUploadQueueID, 'group', $this->id, 'update');
             }
         }
     } catch (Exception $e) {
         Z_Core::logError($e);
     }
     Zotero_DB::commit();
     $this->load();
     return $libraryID;
 }
Ejemplo n.º 5
0
 public function save()
 {
     if (!$this->loaded) {
         Z_Core::debug("Not saving unloaded key {$this->id}");
         return;
     }
     if (!$this->userID) {
         throw new Exception("Cannot save key without userID");
     }
     if (!$this->name) {
         throw new Exception("Cannot save key without name");
     }
     if (strlen($this->name) > 255) {
         throw new Exception("Key name too long", Z_ERROR_KEY_NAME_TOO_LONG);
     }
     Zotero_DB::beginTransaction();
     if (!$this->key) {
         $isNew = true;
         $this->key = Zotero_Keys::generate();
     } else {
         $isNew = false;
     }
     $fields = array('key', 'userID', 'name');
     $sql = "INSERT INTO `keys` (keyID, `key`, userID, name) VALUES (?, ?, ?, ?)";
     $params = array($this->id);
     foreach ($fields as $field) {
         $params[] = $this->{$field};
     }
     $sql .= " ON DUPLICATE KEY UPDATE ";
     $q = array();
     foreach ($fields as $field) {
         $q[] = "`{$field}`=?";
         $params[] = $this->{$field};
     }
     $sql .= implode(", ", $q);
     $insertID = Zotero_DB::query($sql, $params);
     if (!$this->id) {
         if (!$insertID) {
             throw new Exception("Key id not available after INSERT");
         }
         $this->id = $insertID;
     }
     if (!$insertID) {
         $sql = "SELECT * FROM keyPermissions WHERE keyID=?";
         $oldRows = Zotero_DB::query($sql, $this->id);
     }
     $oldPermissions = [];
     $newPermissions = [];
     $librariesToAdd = [];
     $librariesToRemove = [];
     // Massage rows into permissions format
     if (!$isNew && isset($oldRows)) {
         foreach ($oldRows as $row) {
             $oldPermissions[$row['libraryID']][$row['permission']] = !!$row['granted'];
         }
     }
     // Delete existing permissions
     $sql = "DELETE FROM keyPermissions WHERE keyID=?";
     Zotero_DB::query($sql, $this->id);
     if (isset($this->changed['permissions'])) {
         foreach ($this->changed['permissions'] as $libraryID => $p) {
             foreach ($p as $permission => $changed) {
                 $enabled = $this->permissions[$libraryID][$permission];
                 if (!$enabled) {
                     continue;
                 }
                 $sql = "INSERT INTO keyPermissions VALUES (?, ?, ?, ?)";
                 // TODO: support negative permissions
                 Zotero_DB::query($sql, array($this->id, $libraryID, $permission, 1));
                 $newPermissions[$libraryID][$permission] = true;
             }
         }
     }
     $this->permissions = $newPermissions;
     // Send notifications for added and removed API key – library pairs
     if (!$isNew) {
         $librariesToAdd = $this->permissionsDiff($oldPermissions, $newPermissions, $this->userID);
         $librariesToRemove = $this->permissionsDiff($newPermissions, $oldPermissions, $this->userID);
         if ($librariesToAdd) {
             Zotero_Notifier::trigger('add', 'apikey-library', array_map(function ($libraryID) {
                 return $this->key . "-" . $libraryID;
             }, array_unique($librariesToAdd)));
         }
         if ($librariesToRemove) {
             Zotero_Notifier::trigger('remove', 'apikey-library', array_map(function ($libraryID) {
                 return $this->key . "-" . $libraryID;
             }, array_unique($librariesToRemove)));
         }
     }
     Zotero_DB::commit();
     $this->load();
     return $this->id;
 }
Ejemplo n.º 6
0
 public function save()
 {
     if (!$this->loaded) {
         Z_Core::debug("Not saving unloaded key {$this->id}");
         return;
     }
     if (!$this->userID) {
         throw new Exception("Cannot save key without userID");
     }
     if (!$this->name) {
         throw new Exception("Cannot save key without name");
     }
     if (strlen($this->name) > 255) {
         throw new Exception("Key name too long", Z_ERROR_KEY_NAME_TOO_LONG);
     }
     Zotero_DB::beginTransaction();
     if (!$this->key) {
         $this->key = Zotero_Keys::generate();
     }
     $fields = array('key', 'userID', 'name');
     $sql = "INSERT INTO `keys` (keyID, `key`, userID, name) VALUES (?, ?, ?, ?)";
     $params = array($this->id);
     foreach ($fields as $field) {
         $params[] = $this->{$field};
     }
     $sql .= " ON DUPLICATE KEY UPDATE ";
     $q = array();
     foreach ($fields as $field) {
         $q[] = "`{$field}`=?";
         $params[] = $this->{$field};
     }
     $sql .= implode(", ", $q);
     $insertID = Zotero_DB::query($sql, $params);
     if (!$this->id) {
         if (!$insertID) {
             throw new Exception("Key id not available after INSERT");
         }
         $this->id = $insertID;
     }
     // Delete existing permissions
     $sql = "DELETE FROM keyPermissions WHERE keyID=?";
     Zotero_DB::query($sql, $this->id);
     if (isset($this->changed['permissions'])) {
         foreach ($this->changed['permissions'] as $libraryID => $p) {
             foreach ($p as $permission => $changed) {
                 $enabled = $this->permissions[$libraryID][$permission];
                 if (!$enabled) {
                     continue;
                 }
                 $sql = "INSERT INTO keyPermissions VALUES (?, ?, ?, ?)";
                 // TODO: support negative permissions
                 Zotero_DB::query($sql, array($this->id, $libraryID, $permission, 1));
             }
         }
     }
     Zotero_DB::commit();
     $this->load();
     return $this->id;
 }