Example #1
0
 public static function getLibraryURI($libraryID)
 {
     $libraryType = Zotero_Libraries::getType($libraryID);
     switch ($libraryType) {
         case 'user':
             $id = Zotero_Users::getUserIDFromLibraryID($libraryID);
             return self::getUserURI($id);
         case 'group':
             $id = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
             $group = Zotero_Groups::get($id);
             return self::getGroupURI($group);
     }
 }
 public function canAccess($libraryID, $permission = 'library')
 {
     if ($this->super) {
         return true;
     }
     if (!$libraryID) {
         throw new Exception('libraryID not provided');
     }
     // If requested permission is explicitly set
     //
     // This assumes that permissions can't be incorrectly set
     // (e.g., are properly removed when a user loses group access)
     if (!empty($this->permissions[$libraryID][$permission])) {
         return true;
     }
     $libraryType = Zotero_Libraries::getType($libraryID);
     switch ($libraryType) {
         case 'user':
             $userID = Zotero_Users::getUserIDFromLibraryID($libraryID);
             $privacy = $this->getUserPrivacy($userID);
             break;
         case 'group':
             $groupID = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
             // If key has access to all groups, grant access if user
             // has read access to group
             if (!empty($this->permissions[0]['library'])) {
                 $group = Zotero_Groups::get($groupID);
                 // Only members have file access
                 if ($permission == 'files') {
                     return !!$group->getUserRole($this->userID);
                 }
                 if ($group->userCanRead($this->userID)) {
                     return true;
                 }
             }
             $privacy = $this->getGroupPrivacy($groupID);
             break;
         default:
             throw new Exception("Unsupported library type '{$libraryType}'");
     }
     switch ($permission) {
         case 'library':
             return $privacy['publishLibrary'];
         case 'notes':
             return $privacy['publishNotes'];
         default:
             return false;
     }
 }
Example #3
0
 public function laststoragesync()
 {
     $this->allowMethods(array('GET', 'POST'));
     // Deprecated after 3.0, which used auth=1
     if ($this->apiVersion < 2 || !empty($_GET['auth'])) {
         $lastSync = Zotero_Users::getLastStorageSync($this->objectUserID);
     } else {
         $lastSync = Zotero_Libraries::getLastStorageSync($this->objectLibraryID);
     }
     if (!$lastSync) {
         $this->e404();
     }
     echo $lastSync;
     exit;
 }
Example #4
0
 public function laststoragesync()
 {
     if (!$this->httpAuth && !$this->permissions->isSuper()) {
         $this->e403();
     }
     $this->allowMethods(array('GET', 'POST'));
     if ($this->method == 'POST') {
         //Zotero_Users::setLastStorageSync($this->userID);
     }
     // Deprecated after 3.0, which used auth=1
     if ($this->apiVersion < 2 || !empty($_GET['auth'])) {
         $lastSync = Zotero_Users::getLastStorageSync($this->objectUserID);
     } else {
         $lastSync = Zotero_Libraries::getLastStorageSync($this->objectLibraryID);
     }
     if (!$lastSync) {
         $this->e404();
     }
     echo $lastSync;
     exit;
 }
Example #5
0
 /**
  * Converts a Zotero_Item object to a SimpleXMLElement Atom object
  *
  * Note: Increment Z_CONFIG::$CACHE_VERSION_ATOM_ENTRY when changing
  * the response.
  *
  * @param	object				$item		Zotero_Item object
  * @param	string				$content
  * @return	SimpleXMLElement					Item data as SimpleXML element
  */
 public static function convertItemToAtom(Zotero_Item $item, $queryParams, $permissions, $sharedData = null)
 {
     $t = microtime(true);
     // Uncached stuff or parts of the cache key
     $version = $item->version;
     $parent = $item->getSource();
     $isRegularItem = !$parent && $item->isRegularItem();
     $downloadDetails = $permissions->canAccess($item->libraryID, 'files') ? Zotero_Storage::getDownloadDetails($item) : false;
     if ($isRegularItem) {
         $numChildren = $permissions->canAccess($item->libraryID, 'notes') ? $item->numChildren() : $item->numAttachments();
     }
     // <id> changes based on group visibility in v1
     if ($queryParams['v'] < 2) {
         $id = Zotero_URI::getItemURI($item, false, true);
     } else {
         $id = Zotero_URI::getItemURI($item);
     }
     $libraryType = Zotero_Libraries::getType($item->libraryID);
     // Any query parameters that have an effect on the output
     // need to be added here
     $allowedParams = array('content', 'style', 'css', 'linkwrap');
     $cachedParams = Z_Array::filterKeys($queryParams, $allowedParams);
     $cacheVersion = 2;
     $cacheKey = "atomEntry_" . $item->libraryID . "/" . $item->id . "_" . md5($version . json_encode($cachedParams) . ($downloadDetails ? 'hasFile' : '') . ($libraryType == 'group' ? 'id' . $id : '')) . "_" . $queryParams['v'] . "_" . $cacheVersion . (isset(Z_CONFIG::$CACHE_VERSION_ATOM_ENTRY) ? "_" . Z_CONFIG::$CACHE_VERSION_ATOM_ENTRY : "") . (in_array('bib', $queryParams['content']) && isset(Z_CONFIG::$CACHE_VERSION_BIB) ? "_" . Z_CONFIG::$CACHE_VERSION_BIB : "");
     $xmlstr = Z_Core::$MC->get($cacheKey);
     if ($xmlstr) {
         try {
             // TEMP: Strip control characters
             $xmlstr = Zotero_Utilities::cleanString($xmlstr, true);
             $doc = new DOMDocument();
             $doc->loadXML($xmlstr);
             $xpath = new DOMXpath($doc);
             $xpath->registerNamespace('atom', Zotero_Atom::$nsAtom);
             $xpath->registerNamespace('zapi', Zotero_Atom::$nsZoteroAPI);
             $xpath->registerNamespace('xhtml', Zotero_Atom::$nsXHTML);
             // Make sure numChildren reflects the current permissions
             if ($isRegularItem) {
                 $xpath->query('/atom:entry/zapi:numChildren')->item(0)->nodeValue = $numChildren;
             }
             // To prevent PHP from messing with namespace declarations,
             // we have to extract, remove, and then add back <content>
             // subelements. Otherwise the subelements become, say,
             // <default:span xmlns="http://www.w3.org/1999/xhtml"> instead
             // of just <span xmlns="http://www.w3.org/1999/xhtml">, and
             // xmlns:default="http://www.w3.org/1999/xhtml" gets added to
             // the parent <entry>. While you might reasonably think that
             //
             // echo $xml->saveXML();
             //
             // and
             //
             // $xml = new SimpleXMLElement($xml->saveXML());
             // echo $xml->saveXML();
             //
             // would be identical, you would be wrong.
             $multiFormat = !!$xpath->query('/atom:entry/atom:content/zapi:subcontent')->length;
             $contentNodes = array();
             if ($multiFormat) {
                 $contentNodes = $xpath->query('/atom:entry/atom:content/zapi:subcontent');
             } else {
                 $contentNodes = $xpath->query('/atom:entry/atom:content');
             }
             foreach ($contentNodes as $contentNode) {
                 $contentParts = array();
                 while ($contentNode->hasChildNodes()) {
                     $contentParts[] = $doc->saveXML($contentNode->firstChild);
                     $contentNode->removeChild($contentNode->firstChild);
                 }
                 foreach ($contentParts as $part) {
                     if (!trim($part)) {
                         continue;
                     }
                     // Strip the namespace and add it back via SimpleXMLElement,
                     // which keeps it from being changed later
                     if (preg_match('%^<[^>]+xmlns="http://www.w3.org/1999/xhtml"%', $part)) {
                         $part = preg_replace('%^(<[^>]+)xmlns="http://www.w3.org/1999/xhtml"%', '$1', $part);
                         $html = new SimpleXMLElement($part);
                         $html['xmlns'] = "http://www.w3.org/1999/xhtml";
                         $subNode = dom_import_simplexml($html);
                         $importedNode = $doc->importNode($subNode, true);
                         $contentNode->appendChild($importedNode);
                     } else {
                         if (preg_match('%^<[^>]+xmlns="http://zotero.org/ns/transfer"%', $part)) {
                             $part = preg_replace('%^(<[^>]+)xmlns="http://zotero.org/ns/transfer"%', '$1', $part);
                             $html = new SimpleXMLElement($part);
                             $html['xmlns'] = "http://zotero.org/ns/transfer";
                             $subNode = dom_import_simplexml($html);
                             $importedNode = $doc->importNode($subNode, true);
                             $contentNode->appendChild($importedNode);
                         } else {
                             $docFrag = $doc->createDocumentFragment();
                             $docFrag->appendXML($part);
                             $contentNode->appendChild($docFrag);
                         }
                     }
                 }
             }
             $xml = simplexml_import_dom($doc);
             StatsD::timing("api.items.itemToAtom.cached", (microtime(true) - $t) * 1000);
             StatsD::increment("memcached.items.itemToAtom.hit");
             // Skip the cache every 10 times for now, to ensure cache sanity
             if (Z_Core::probability(10)) {
                 $xmlstr = $xml->saveXML();
             } else {
                 return $xml;
             }
         } catch (Exception $e) {
             error_log($xmlstr);
             error_log("WARNING: " . $e);
         }
     }
     $content = $queryParams['content'];
     $contentIsHTML = sizeOf($content) == 1 && $content[0] == 'html';
     $contentParamString = urlencode(implode(',', $content));
     $style = $queryParams['style'];
     $entry = '<?xml version="1.0" encoding="UTF-8"?>' . '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>';
     $xml = new SimpleXMLElement($entry);
     $title = $item->getDisplayTitle(true);
     $title = $title ? $title : '[Untitled]';
     $xml->title = $title;
     $author = $xml->addChild('author');
     $createdByUserID = null;
     $lastModifiedByUserID = null;
     switch (Zotero_Libraries::getType($item->libraryID)) {
         case 'group':
             $createdByUserID = $item->createdByUserID;
             // Used for zapi:lastModifiedByUser below
             $lastModifiedByUserID = $item->lastModifiedByUserID;
             break;
     }
     if ($createdByUserID) {
         $author->name = Zotero_Users::getUsername($createdByUserID);
         $author->uri = Zotero_URI::getUserURI($createdByUserID);
     } else {
         $author->name = Zotero_Libraries::getName($item->libraryID);
         $author->uri = Zotero_URI::getLibraryURI($item->libraryID);
     }
     $xml->id = $id;
     $xml->published = Zotero_Date::sqlToISO8601($item->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($item->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $href = Zotero_API::getItemURI($item);
     if (!$contentIsHTML) {
         $href .= "?content={$contentParamString}";
     }
     $link['href'] = $href;
     if ($parent) {
         // TODO: handle group items?
         $parentItem = Zotero_Items::get($item->libraryID, $parent);
         $link = $xml->addChild("link");
         $link['rel'] = "up";
         $link['type'] = "application/atom+xml";
         $href = Zotero_API::getItemURI($parentItem);
         if (!$contentIsHTML) {
             $href .= "?content={$contentParamString}";
         }
         $link['href'] = $href;
     }
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getItemURI($item, true);
     // If appropriate permissions and the file is stored in ZFS, get file request link
     if ($downloadDetails) {
         $details = $downloadDetails;
         $link = $xml->addChild('link');
         $link['rel'] = 'enclosure';
         $type = $item->attachmentMIMEType;
         if ($type) {
             $link['type'] = $type;
         }
         $link['href'] = $details['url'];
         if (!empty($details['filename'])) {
             $link['title'] = $details['filename'];
         }
         if (isset($details['size'])) {
             $link['length'] = $details['size'];
         }
     }
     $xml->addChild('zapi:key', $item->key, Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:version', $item->version, Zotero_Atom::$nsZoteroAPI);
     if ($lastModifiedByUserID) {
         $xml->addChild('zapi:lastModifiedByUser', Zotero_Users::getUsername($lastModifiedByUserID), Zotero_Atom::$nsZoteroAPI);
     }
     $xml->addChild('zapi:itemType', Zotero_ItemTypes::getName($item->itemTypeID), Zotero_Atom::$nsZoteroAPI);
     if ($isRegularItem) {
         $val = $item->creatorSummary;
         if ($val !== '') {
             $xml->addChild('zapi:creatorSummary', htmlspecialchars($val), Zotero_Atom::$nsZoteroAPI);
         }
         $val = $item->getField('date', true, true, true);
         if ($val !== '') {
             if ($queryParams['v'] < 3) {
                 $val = substr($val, 0, 4);
                 if ($val !== '0000') {
                     $xml->addChild('zapi:year', $val, Zotero_Atom::$nsZoteroAPI);
                 }
             } else {
                 $sqlDate = Zotero_Date::multipartToSQL($val);
                 if (substr($sqlDate, 0, 4) !== '0000') {
                     $xml->addChild('zapi:parsedDate', Zotero_Date::sqlToISO8601($sqlDate), Zotero_Atom::$nsZoteroAPI);
                 }
             }
         }
         $xml->addChild('zapi:numChildren', $numChildren, Zotero_Atom::$nsZoteroAPI);
     }
     if ($queryParams['v'] < 3) {
         $xml->addChild('zapi:numTags', $item->numTags(), Zotero_Atom::$nsZoteroAPI);
     }
     $xml->content = '';
     //
     // DOM XML from here on out
     //
     $contentNode = dom_import_simplexml($xml->content);
     $domDoc = $contentNode->ownerDocument;
     $multiFormat = sizeOf($content) > 1;
     // Create a root XML document for multi-format responses
     if ($multiFormat) {
         $contentNode->setAttribute('type', 'application/xml');
         /*$multicontent = $domDoc->createElementNS(
         			Zotero_Atom::$nsZoteroAPI, 'multicontent'
         		);
         		$contentNode->appendChild($multicontent);*/
     }
     foreach ($content as $type) {
         // Set the target to either the main <content>
         // or a <multicontent> <content>
         if (!$multiFormat) {
             $target = $contentNode;
         } else {
             $target = $domDoc->createElementNS(Zotero_Atom::$nsZoteroAPI, 'subcontent');
             $contentNode->appendChild($target);
         }
         $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:type", $type);
         if ($type == 'html') {
             if (!$multiFormat) {
                 $target->setAttribute('type', 'xhtml');
             }
             $div = $domDoc->createElementNS(Zotero_Atom::$nsXHTML, 'div');
             $target->appendChild($div);
             $html = $item->toHTML(true);
             $subNode = dom_import_simplexml($html);
             $importedNode = $domDoc->importNode($subNode, true);
             $div->appendChild($importedNode);
         } else {
             if ($type == 'citation') {
                 if (!$multiFormat) {
                     $target->setAttribute('type', 'xhtml');
                 }
                 if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                     $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                 } else {
                     if ($sharedData !== null) {
                         //error_log("Citation not found in sharedData -- retrieving individually");
                     }
                     $html = Zotero_Cite::getCitationFromCiteServer($item, $queryParams);
                 }
                 $html = new SimpleXMLElement($html);
                 $html['xmlns'] = Zotero_Atom::$nsXHTML;
                 $subNode = dom_import_simplexml($html);
                 $importedNode = $domDoc->importNode($subNode, true);
                 $target->appendChild($importedNode);
             } else {
                 if ($type == 'bib') {
                     if (!$multiFormat) {
                         $target->setAttribute('type', 'xhtml');
                     }
                     if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                         $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                     } else {
                         if ($sharedData !== null) {
                             //error_log("Bibliography not found in sharedData -- retrieving individually");
                         }
                         $html = Zotero_Cite::getBibliographyFromCitationServer(array($item), $queryParams);
                     }
                     $html = new SimpleXMLElement($html);
                     $html['xmlns'] = Zotero_Atom::$nsXHTML;
                     $subNode = dom_import_simplexml($html);
                     $importedNode = $domDoc->importNode($subNode, true);
                     $target->appendChild($importedNode);
                 } else {
                     if ($type == 'json') {
                         if ($queryParams['v'] < 2) {
                             $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:etag", $item->etag);
                         }
                         $textNode = $domDoc->createTextNode($item->toJSON(false, $queryParams, true));
                         $target->appendChild($textNode);
                     } else {
                         if ($type == 'csljson') {
                             $arr = $item->toCSLItem();
                             $json = Zotero_Utilities::formatJSON($arr);
                             $textNode = $domDoc->createTextNode($json);
                             $target->appendChild($textNode);
                         } else {
                             if (in_array($type, Zotero_Translate::$exportFormats)) {
                                 $export = Zotero_Translate::doExport(array($item), $type);
                                 $target->setAttribute('type', $export['mimeType']);
                                 // Insert XML into document
                                 if (preg_match('/\\+xml$/', $export['mimeType'])) {
                                     // Strip prolog
                                     $body = preg_replace('/^<\\?xml.+\\n/', "", $export['body']);
                                     $subNode = $domDoc->createDocumentFragment();
                                     $subNode->appendXML($body);
                                     $target->appendChild($subNode);
                                 } else {
                                     $textNode = $domDoc->createTextNode($export['body']);
                                     $target->appendChild($textNode);
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     // TEMP
     if ($xmlstr) {
         $uncached = $xml->saveXML();
         if ($xmlstr != $uncached) {
             $uncached = str_replace('<zapi:year></zapi:year>', '<zapi:year/>', $uncached);
             $uncached = str_replace('<content zapi:type="none"></content>', '<content zapi:type="none"/>', $uncached);
             $uncached = str_replace('<zapi:subcontent zapi:type="coins" type="text/html"></zapi:subcontent>', '<zapi:subcontent zapi:type="coins" type="text/html"/>', $uncached);
             $uncached = str_replace('<title></title>', '<title/>', $uncached);
             $uncached = str_replace('<note></note>', '<note/>', $uncached);
             $uncached = str_replace('<path></path>', '<path/>', $uncached);
             $uncached = str_replace('<td></td>', '<td/>', $uncached);
             if ($xmlstr != $uncached) {
                 error_log("Cached Atom item entry does not match");
                 error_log("  Cached: " . $xmlstr);
                 error_log("Uncached: " . $uncached);
                 Z_Core::$MC->set($cacheKey, $uncached, 3600);
                 // 1 hour for now
             }
         }
     } else {
         $xmlstr = $xml->saveXML();
         Z_Core::$MC->set($cacheKey, $xmlstr, 3600);
         // 1 hour for now
         StatsD::timing("api.items.itemToAtom.uncached", (microtime(true) - $t) * 1000);
         StatsD::increment("memcached.items.itemToAtom.miss");
     }
     return $xml;
 }
Example #6
0
 public function setUp()
 {
     Zotero_Users::clearAllData(self::$config['userID']);
 }
Example #7
0
 protected function setKeyPermissions($keyObj, $accessElement)
 {
     foreach ($accessElement as $accessField => $accessVal) {
         // 'write' is handled below
         if ($accessField == 'write') {
             continue;
         }
         // Group library access (<access group="23456"/>)
         if ($accessField == 'group') {
             // Grant access to all groups
             if ($accessVal === 0) {
                 $keyObj->setPermission(0, 'group', true);
                 $keyObj->setPermission(0, 'write', $accessElement['write']);
             } else {
                 $group = Zotero_Groups::get($accessVal);
                 if (!$group) {
                     $this->e400("Group not found");
                 }
                 if (!$group->hasUser($keyObj->userID)) {
                     $this->e400("User {$this->id} is not a member of group {$group->id}");
                 }
                 $keyObj->setPermission($group->libraryID, 'library', true);
                 $keyObj->setPermission($group->libraryID, 'write', $accessElement['write']);
             }
         } else {
             $libraryID = Zotero_Users::getLibraryIDFromUserID($keyObj->userID);
             $keyObj->setPermission($libraryID, $accessField, $accessVal);
             $keyObj->setPermission($libraryID, 'write', $accessElement['write']);
         }
     }
 }
Example #8
0
 public static function getByUserID($userID)
 {
     $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     return self::getByLibraryID($libraryID);
 }
Example #9
0
 private static function getDeletedObjectIDs($userID, $timestamp, $includeAllUserObjects = false)
 {
     /*
     $sql = "SELECT version FROM version WHERE schema='syncdeletelog'";
     $syncLogStart = Zotero_DB::valueQuery($sql);
     if (!$syncLogStart) {
     	throw ('Sync log start time not found');
     }
     */
     /*
     // Last sync time is before start of log
     if ($lastSyncDate && new Date($syncLogStart * 1000) > $lastSyncDate) {
     	return -1;
     }
     */
     // Personal library
     $shardID = Zotero_Shards::getByUserID($userID);
     $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     $shardLibraryIDs[$shardID] = array($libraryID);
     // Group libraries
     if ($includeAllUserObjects) {
         $groupIDs = Zotero_Groups::getUserGroups($userID);
         if ($groupIDs) {
             // Separate groups into shards for querying
             foreach ($groupIDs as $groupID) {
                 $libraryID = Zotero_Groups::getLibraryIDFromGroupID($groupID);
                 $shardID = Zotero_Shards::getByLibraryID($libraryID);
                 if (!isset($shardLibraryIDs[$shardID])) {
                     $shardLibraryIDs[$shardID] = array();
                 }
                 $shardLibraryIDs[$shardID][] = $libraryID;
             }
         }
     }
     // Send query at each shard
     $rows = array();
     foreach ($shardLibraryIDs as $shardID => $libraryIDs) {
         $sql = "SELECT libraryID, objectType, id, timestamp\n\t\t\t\t\tFROM syncDeleteLogIDs WHERE libraryID IN (" . implode(', ', array_fill(0, sizeOf($libraryIDs), '?')) . ")";
         $params = $libraryIDs;
         if ($timestamp) {
             // Send any entries from before these were being properly sent
             if ($timestamp < 1260778500) {
                 $sql .= " AND (timestamp >= FROM_UNIXTIME(?) OR timestamp BETWEEN 1257968068 AND FROM_UNIXTIME(?))";
                 $params[] = $timestamp;
                 $params[] = 1260778500;
             } else {
                 $sql .= " AND timestamp >= FROM_UNIXTIME(?)";
                 $params[] = $timestamp;
             }
         }
         $sql .= " ORDER BY timestamp";
         $shardRows = Zotero_DB::query($sql, $params, $shardID);
         if ($shardRows) {
             $rows = array_merge($rows, $shardRows);
         }
     }
     if (!$rows) {
         return false;
     }
     $deletedIDs = array('groups' => array());
     foreach ($rows as $row) {
         $type = $row['objectType'] . 's';
         $deletedIDs[$type][] = $row['id'];
     }
     return $deletedIDs;
 }
Example #10
0
 private static function updateUser($userID, $username)
 {
     if (Zotero_Users::exists($userID)) {
         $currentUsername = Zotero_Users::getUsername($userID, true);
         if ($currentUsername != $username) {
             Zotero_Users::update($userID, $username);
         }
     } else {
         Zotero_Users::add($userID, $username);
         Zotero_Users::update($userID);
     }
 }
Example #11
0
 public function toJSON()
 {
     if (($this->id || $this->key) && !$this->loaded) {
         $this->load();
     }
     $json = [];
     $json['key'] = $this->key;
     $json['userID'] = $this->userID;
     $json['username'] = Zotero_Users::getUsername($this->userID);
     $json['name'] = $this->name;
     if ($this->permissions) {
         $json['access'] = ['user' => [], 'groups' => []];
         foreach ($this->permissions as $libraryID => $p) {
             // group="all" is stored as libraryID 0
             if ($libraryID === 0) {
                 $json['access']['groups']['all']['library'] = true;
                 $json['access']['groups']['all']['write'] = !empty($p['write']);
             } else {
                 $type = Zotero_Libraries::getType($libraryID);
                 switch ($type) {
                     case 'user':
                         $json['access']['user']['library'] = true;
                         foreach ($p as $permission => $granted) {
                             if ($permission == 'library') {
                                 continue;
                             }
                             $json['access']['user'][$permission] = (bool) $granted;
                         }
                         break;
                     case 'group':
                         $groupID = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
                         $json['access']['groups'][$groupID]['library'] = true;
                         $json['access']['groups'][$groupID]['write'] = !empty($p['write']);
                         break;
                 }
             }
         }
         if (sizeOf($json['access']['user']) === 0) {
             unset($json['access']['user']);
         }
         if (sizeOf($json['access']['groups']) === 0) {
             unset($json['access']['groups']);
         }
     }
     $json['dateAdded'] = Zotero_Date::sqlToISO8601($this->dateAdded);
     if ($this->lastUsed != '0000-00-00 00:00:00') {
         $json['lastUsed'] = Zotero_Date::sqlToISO8601($this->lastUsed);
     }
     $ips = $this->getRecentIPs();
     if ($ips) {
         $json['recentIPs'] = $ips;
     }
     return $json;
 }
Example #12
0
 /**
  * This should be called after canAccess()
  */
 public function canWrite($libraryID)
 {
     if ($this->super) {
         return true;
     }
     if ($libraryID === 0) {
         return false;
     }
     if (!$libraryID) {
         throw new Exception('libraryID not provided');
     }
     if (!empty($this->permissions[$libraryID]['write'])) {
         return true;
     }
     $libraryType = Zotero_Libraries::getType($libraryID);
     switch ($libraryType) {
         case 'user':
             return false;
             // Write permissions match key's write access to user library
         // Write permissions match key's write access to user library
         case 'publications':
             $userLibraryID = Zotero_Users::getLibraryIDFromUserID($this->userID);
             return $this->canWrite($userLibraryID);
         case 'group':
             $groupID = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
             // If key has write access to all groups, grant access if user
             // has write access to group
             if (!empty($this->permissions[0]['write'])) {
                 $group = Zotero_Groups::get($groupID);
                 return $group->userCanEdit($this->userID);
             }
             return false;
         default:
             throw new Exception("Unsupported library type '{$libraryType}'");
     }
 }
Example #13
0
 public function groups()
 {
     $groupID = $this->objectGroupID;
     //
     // Add a group
     //
     if ($this->method == 'POST') {
         if (!$this->permissions->isSuper()) {
             $this->e403();
         }
         if ($groupID) {
             $this->e400("POST requests cannot end with a groupID (did you mean PUT?)");
         }
         try {
             $group = @new SimpleXMLElement($this->body);
         } catch (Exception $e) {
             $this->e400("{$this->method} data is not valid XML");
         }
         if ((int) $group['id']) {
             $this->e400("POST requests cannot contain a groupID in '" . $this->body . "'");
         }
         $fields = $this->getFieldsFromGroupXML($group);
         Zotero_DB::beginTransaction();
         try {
             $group = new Zotero_Group();
             foreach ($fields as $field => $val) {
                 $group->{$field} = $val;
             }
             $group->save();
         } catch (Exception $e) {
             if (strpos($e->getMessage(), "Invalid") === 0) {
                 $this->e400($e->getMessage() . " in " . $this->body . "'");
             }
             switch ($e->getCode()) {
                 case Z_ERROR_GROUP_NAME_UNAVAILABLE:
                     $this->e400($e->getMessage());
                 default:
                     $this->handleException($e);
             }
         }
         $this->queryParams['content'] = array('full');
         $this->responseXML = $group->toAtom($this->queryParams);
         Zotero_DB::commit();
         $url = Zotero_API::getGroupURI($group);
         $this->responseCode = 201;
         header("Location: " . $url, false, 201);
         $this->end();
     }
     //
     // Update a group
     //
     if ($this->method == 'PUT') {
         if (!$this->permissions->isSuper()) {
             $this->e403();
         }
         if (!$groupID) {
             $this->e400("PUT requests must end with a groupID (did you mean POST?)");
         }
         try {
             $group = @new SimpleXMLElement($this->body);
         } catch (Exception $e) {
             $this->e400("{$this->method} data is not valid XML");
         }
         $fields = $this->getFieldsFromGroupXML($group);
         // Group id is optional, but, if it's there, make sure it matches
         $id = (string) $group['id'];
         if ($id && $id != $groupID) {
             $this->e400("Group ID {$id} does not match group ID {$groupID} from URI");
         }
         Zotero_DB::beginTransaction();
         try {
             $group = Zotero_Groups::get($groupID);
             if (!$group) {
                 $this->e404("Group {$groupID} does not exist");
             }
             foreach ($fields as $field => $val) {
                 $group->{$field} = $val;
             }
             if ($this->ifUnmodifiedSince && strtotime($group->dateModified) > $this->ifUnmodifiedSince) {
                 $this->e412();
             }
             $group->save();
         } catch (Exception $e) {
             if (strpos($e->getMessage(), "Invalid") === 0) {
                 $this->e400($e->getMessage() . " in " . $this->body . "'");
             } else {
                 if ($e->getCode() == Z_ERROR_GROUP_DESCRIPTION_TOO_LONG) {
                     $this->e400($e->getMessage());
                 }
             }
             $this->handleException($e);
         }
         $this->queryParams['content'] = array('full');
         $this->responseXML = $group->toAtom($this->queryParams);
         Zotero_DB::commit();
         $this->end();
     }
     //
     // Delete a group
     //
     if ($this->method == 'DELETE') {
         if (!$this->permissions->isSuper()) {
             $this->e403();
         }
         if (!$groupID) {
             $this->e400("DELETE requests must end with a groupID");
         }
         Zotero_DB::beginTransaction();
         $group = Zotero_Groups::get($groupID);
         if (!$group) {
             $this->e404("Group {$groupID} does not exist");
         }
         $group->erase();
         Zotero_DB::commit();
         header("HTTP/1.1 204 No Content");
         exit;
     }
     //
     // View one or more groups
     //
     // Single group
     if ($groupID) {
         $group = Zotero_Groups::get($groupID);
         if (!$this->permissions->canAccess($this->objectLibraryID)) {
             $this->e403();
         }
         if (!$group) {
             $this->e404("Group not found");
         }
         if ($this->apiVersion >= 3) {
             $this->libraryVersion = $group->version;
         } else {
             header("ETag: " . $group->etag);
         }
         if ($this->method == 'HEAD') {
             $this->end();
         }
         switch ($this->queryParams['format']) {
             case 'atom':
                 $this->responseXML = $group->toAtom($this->queryParams);
                 break;
             case 'json':
                 $json = $group->toResponseJSON($this->queryParams);
                 echo Zotero_Utilities::formatJSON($json);
                 break;
             default:
                 throw new Exception("Unexpected format '" . $this->queryParams['format'] . "'");
         }
     } else {
         if ($this->objectUserID) {
             $title = Zotero_Users::getUsername($this->objectUserID) . "’s Groups";
         } else {
             // For now, only root can do unrestricted group searches
             if (!$this->permissions->isSuper()) {
                 $this->e403();
             }
             $title = "Groups";
         }
         try {
             $results = Zotero_Groups::getAllAdvanced($this->objectUserID, $this->queryParams, $this->permissions);
         } catch (Exception $e) {
             switch ($e->getCode()) {
                 case Z_ERROR_INVALID_GROUP_TYPE:
                     $this->e400($e->getMessage());
             }
             throw $e;
         }
         $options = ['action' => $this->action, 'uri' => $this->uri, 'results' => $results, 'requestParams' => $this->queryParams, 'permissions' => $this->permissions, 'head' => $this->method == 'HEAD'];
         switch ($this->queryParams['format']) {
             case 'atom':
                 $this->responseXML = Zotero_API::multiResponse(array_merge($options, ['title' => $title]));
                 break;
             case 'json':
                 Zotero_API::multiResponse($options);
                 break;
             case 'etags':
             case 'versions':
                 $prop = substr($this->queryParams['format'], 0, -1);
                 // remove 's'
                 $newResults = [];
                 foreach ($results['results'] as $group) {
                     $newResults[$group->id] = $group->{$prop};
                 }
                 $options['results']['results'] = $newResults;
                 Zotero_API::multiResponse($options, 'versions');
                 break;
             default:
                 throw new Exception("Unexpected format '" . $this->queryParams['format'] . "'");
         }
     }
     $this->end();
 }
Example #14
0
 public static function getValidUsers($userIDs)
 {
     if (!$userIDs) {
         return array();
     }
     $newUserIDs = array();
     foreach ($userIDs as $id) {
         if (Zotero_Users::isValidUser($id)) {
             $newUserIDs[] = $id;
         }
     }
     return $newUserIDs;
 }
Example #15
0
 public static function getAllAdvanced($userID = false, $params = array(), $permissions = null)
 {
     $buffer = 20;
     $maxTimes = 3;
     $groups = array();
     $start = !empty($params['start']) ? $params['start'] : 0;
     $limit = !empty($params['limit']) ? $params['limit'] + $buffer : false;
     $totalResults = null;
     $times = 0;
     while (true) {
         if ($times > 0) {
             Z_Core::logError('Getting more groups in Zotero_Groups::getAllAdvanced()');
         }
         $calcFoundRows = !$totalResults;
         $cacheFoundRows = $calcFoundRows && !$userID;
         // If we don't yet have a row count and this isn't a user-specific search,
         // try to get a cached row count.
         if ($cacheFoundRows) {
             $foundRowsCacheKey = self::getCacheComponentFromParam($params, 'q') . "," . self::getCacheComponentFromParam($params, 'fq');
             $foundRowsTTL = 180;
             $foundRowsLockTTL = 10;
             $foundRowsRealTTL = 3600;
             $obj = Z_Core::$MC->get($foundRowsCacheKey);
             if ($obj) {
                 $foundRows = $obj['rows'];
                 $exp = $obj['exp'];
                 // If count was found but is past the expiration time, check if another
                 // request is getting the row count, and fetch it if not
                 if ($exp < time()) {
                     if (!Z_Core::$MC->add($foundRowsCacheKey . "Lock", true, $foundRowsLockTTL)) {
                         $calcFoundRows = false;
                     }
                 } else {
                     $calcFoundRows = false;
                 }
             }
         }
         $sql = "SELECT " . ($calcFoundRows ? "SQL_CALC_FOUND_ROWS " : "") . "G.groupID, GUO.userID AS ownerUserID FROM groups G " . "JOIN groupUsers GUO ON (G.groupID=GUO.groupID AND GUO.role='owner') ";
         $sqlParams = array();
         if ($userID) {
             $sql .= "JOIN groupUsers GUA ON (G.groupID=GUA.groupID) WHERE GUA.userID=? ";
             $sqlParams[] = $userID;
         }
         $paramSQL = "";
         $includeEmpty = false;
         if (!empty($params['q'])) {
             if (!is_array($params['q'])) {
                 $params['q'] = array($params['q']);
             }
             foreach ($params['q'] as $q) {
                 $field = explode(":", $q);
                 if (sizeOf($field) == 2) {
                     switch ($field[0]) {
                         case 'slug':
                             $includeEmpty = true;
                             break;
                         default:
                             throw new Exception("Cannot search by group field '{$field[0]}'", Z_ERROR_INVALID_GROUP_TYPE);
                     }
                     $paramSQL .= "AND " . $field[0];
                     // If first character is '-', negate
                     $paramSQL .= $field[0][0] == '-' ? '!' : '';
                     $paramSQL .= "=? ";
                     $sqlParams[] = $field[1];
                 } else {
                     $paramSQL .= "AND name LIKE ? ";
                     $sqlParams[] = "%{$q}%";
                 }
             }
         }
         if (!$userID) {
             if ($includeEmpty) {
                 $sql .= "WHERE 1 ";
             } else {
                 // Don't include groups that have never had items
                 $sql .= "JOIN libraries L ON (G.libraryID=L.libraryID)\n\t\t\t\t\t\t\tWHERE L.lastUpdated != '0000-00-00 00:00:00' ";
             }
         }
         $sql .= $paramSQL;
         if (!empty($params['fq'])) {
             if (!is_array($params['fq'])) {
                 $params['fq'] = array($params['fq']);
             }
             foreach ($params['fq'] as $fq) {
                 $facet = explode(":", $fq);
                 if (sizeOf($facet) == 2 && preg_match('/-?GroupType/', $facet[0])) {
                     switch ($facet[1]) {
                         case 'PublicOpen':
                         case 'PublicClosed':
                         case 'Private':
                             break;
                         default:
                             throw new Exception("Invalid group type '{$facet[1]}'", Z_ERROR_INVALID_GROUP_TYPE);
                     }
                     $sql .= "AND type";
                     // If first character is '-', negate
                     $sql .= $facet[0][0] == '-' ? '!' : '';
                     $sql .= "=? ";
                     $sqlParams[] = $facet[1];
                 }
             }
         }
         if (!empty($params['sort'])) {
             $order = $params['sort'];
             if ($order == 'title') {
                 $order = 'name';
             }
             $sql .= "ORDER BY {$order}";
             if (!empty($params['direction'])) {
                 $sql .= " " . $params['direction'] . " ";
             }
         }
         // Limit is set $buffer higher than the actual limit, in case some groups are
         // removed during access checks
         //
         // Actual limiting is done below
         if ($limit) {
             $sql .= "LIMIT ?, ?";
             $sqlParams[] = $start;
             $sqlParams[] = $limit;
         }
         $rows = Zotero_DB::query($sql, $sqlParams);
         if (!$rows) {
             break;
         }
         if (is_null($totalResults)) {
             if ($calcFoundRows) {
                 $foundRows = Zotero_DB::valueQuery("SELECT FOUND_ROWS()");
                 // Cache found rows count, and store earlier expiration time so that one
                 // request can trigger a recalculation before cached value expires
                 if ($cacheFoundRows) {
                     Z_Core::$MC->set($foundRowsCacheKey, ['rows' => $foundRows, 'exp' => time() + $foundRowsTTL], $foundRowsRealTTL);
                 }
             }
             $totalResults = $foundRows;
         }
         // Include only groups with non-banned owners
         $owners = array();
         foreach ($rows as $row) {
             $owners[] = $row['ownerUserID'];
         }
         $owners = Zotero_Users::getValidUsers($owners);
         $ids = array();
         foreach ($rows as $row) {
             if (!in_array($row['ownerUserID'], $owners)) {
                 $totalResults--;
                 continue;
             }
             $ids[] = $row['groupID'];
         }
         $batchStartPos = sizeOf($groups);
         foreach ($ids as $id) {
             $group = Zotero_Groups::get($id, true);
             $groups[] = $group;
         }
         // Remove groups that can't be accessed
         if ($permissions) {
             for ($i = $batchStartPos; $i < sizeOf($groups); $i++) {
                 if (!$permissions->canAccess($groups[$i]->libraryID, 'view')) {
                     array_splice($groups, $i, 1);
                     $i--;
                     $totalResults--;
                 }
             }
         }
         $times++;
         if ($times == $maxTimes) {
             Z_Core::logError('Too many queries in Zotero_Groups::getAllAdvanced()');
             break;
         }
         if (empty($params['limit'])) {
             break;
         }
         // If we have enough groups to fill the limit, stop
         if (sizeOf($groups) > $params['limit']) {
             break;
         }
         // If there no more rows, stop
         if ($start + sizeOf($rows) >= $foundRows) {
             break;
         }
         $start = $start + sizeOf($rows);
         // Get number we still need plus the buffer or all remaining, whichever is lower
         $limit = min($params['limit'] - sizeOf($groups) + $buffer, $foundRows - $start);
     }
     // TODO: generate previous start value
     if (!$groups) {
         return array('results' => array(), 'total' => 0);
     }
     // Fake limiting -- we can't just use SQL limit because
     // some groups might be inaccessible
     if (!empty($params['limit'])) {
         $groups = array_slice($groups, 0, $params['limit']);
     }
     $results = array('results' => $groups, 'total' => $totalResults);
     return $results;
 }
 public static function isEditable($obj)
 {
     $type = static::field('object');
     // Only enforce for sync controller for now
     if (empty($GLOBALS['controller']) || !$GLOBALS['controller'] instanceof SyncController) {
         return true;
     }
     // Make sure user has access privileges to delete
     $userID = $GLOBALS['controller']->userID;
     if (!$userID) {
         return true;
     }
     $objectLibraryID = $obj->libraryID;
     $libraryType = Zotero_Libraries::getType($objectLibraryID);
     switch ($libraryType) {
         case 'user':
             if (!empty($GLOBALS['controller']->userLibraryID)) {
                 $userLibraryID = $GLOBALS['controller']->userLibraryID;
             } else {
                 $userLibraryID = Zotero_Users::getLibraryIDFromUserID($userID);
             }
             if ($objectLibraryID != $userLibraryID) {
                 return false;
             }
             return true;
         case 'group':
             $groupID = Zotero_Groups::getGroupIDFromLibraryID($objectLibraryID);
             $group = Zotero_Groups::get($groupID);
             if (!$group->hasUser($userID) || !$group->userCanEdit($userID)) {
                 return false;
             }
             if ($type == 'item' && $obj->isImportedAttachment() && !$group->userCanEditFiles($userID)) {
                 return false;
             }
             return true;
         default:
             throw new Exception("Unsupported library type '{$libraryType}'");
     }
 }
Example #17
0
 public static function toJSON($libraryID)
 {
     // TODO: cache
     $libraryType = Zotero_Libraries::getType($libraryID);
     if ($libraryType == 'user') {
         $objectUserID = Zotero_Users::getUserIDFromLibraryID($libraryID);
         $json = ['type' => $libraryType, 'id' => $objectUserID, 'name' => self::getName($libraryID), 'links' => ['alternate' => ['href' => Zotero_URI::getUserURI($objectUserID, true), 'type' => 'text/html']]];
     } else {
         if ($libraryType == 'publications') {
             $objectUserID = Zotero_Users::getUserIDFromLibraryID($libraryID);
             $json = ['type' => $libraryType, 'id' => $objectUserID, 'name' => self::getName($libraryID), 'links' => ['alternate' => ['href' => Zotero_URI::getUserURI($objectUserID, true) . "/publications", 'type' => 'text/html']]];
         } else {
             if ($libraryType == 'group') {
                 $objectGroupID = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
                 $group = Zotero_Groups::get($objectGroupID);
                 $json = ['type' => $libraryType, 'id' => $objectGroupID, 'name' => self::getName($libraryID), 'links' => ['alternate' => ['href' => Zotero_URI::getGroupURI($group, true), 'type' => 'text/html']]];
             } else {
                 throw new Exception("Invalid library type '{$libraryType}'");
             }
         }
     }
     return $json;
 }
Example #18
0
 public static function getUserLibraries($userID)
 {
     return array_merge(array(Zotero_Users::getLibraryIDFromUserID($userID)), Zotero_Groups::getUserGroupLibraries($userID));
 }
Example #19
0
 public static function getUserUsage($userID)
 {
     $usage = array();
     $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     $sql = "SELECT SUM(size) AS bytes FROM storageFileItems\n\t\t\t\tJOIN items USING (itemID) WHERE libraryID=?";
     $libraryBytes = Zotero_DB::valueQuery($sql, $libraryID, Zotero_Shards::getByLibraryID($libraryID));
     $usage['library'] = round($libraryBytes / 1024 / 1024, 1);
     $groupBytes = 0;
     $usage['groups'] = array();
     $ownedLibraries = Zotero_Groups::getUserOwnedGroupLibraries($userID);
     if ($ownedLibraries) {
         $shardIDs = Zotero_Groups::getUserGroupShards($userID);
         foreach ($shardIDs as $shardID) {
             $sql = "SELECT libraryID, SUM(size) AS `bytes` FROM storageFileItems\n\t\t\t\t\t\tJOIN items I USING (itemID)\n\t\t\t\t\t\tWHERE libraryID IN\n\t\t\t\t\t\t(" . implode(', ', array_fill(0, sizeOf($ownedLibraries), '?')) . ")\n\t\t\t\t\t\tGROUP BY libraryID WITH ROLLUP";
             $libraries = Zotero_DB::query($sql, $ownedLibraries, $shardID);
             if ($libraries) {
                 foreach ($libraries as $library) {
                     if ($library['libraryID']) {
                         $usage['groups'][] = array('id' => Zotero_Groups::getGroupIDFromLibraryID($library['libraryID']), 'usage' => round($library['bytes'] / 1024 / 1024, 1));
                     } else {
                         $groupBytes += $library['bytes'];
                     }
                 }
             }
         }
     }
     $usage['total'] = round(($libraryBytes + $groupBytes) / 1024 / 1024, 1);
     return $usage;
 }
Example #20
0
 public static function getLibraryURI($libraryID)
 {
     $libraryType = Zotero_Libraries::getType($libraryID);
     switch ($libraryType) {
         case 'user':
             $id = Zotero_Users::getUserIDFromLibraryID($libraryID);
             return self::getBaseURI() . "users/{$id}";
         case 'group':
             $id = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
             return self::getBaseURI() . "groups/{$id}";
     }
 }
Example #21
0
 /**
  * For HTTP Auth and session-based auth, generate blanket user permissions
  * manually, since there's no key object
  */
 protected function grantUserPermissions($userID)
 {
     $this->permissions = new Zotero_Permissions($userID);
     $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     // Grant user permissions on own library and all groups
     $this->permissions->setPermission($libraryID, 'library', true);
     $this->permissions->setPermission($libraryID, 'files', true);
     $this->permissions->setPermission($libraryID, 'notes', true);
     $this->permissions->setPermission($libraryID, 'write', true);
     $this->permissions->setPermission(0, 'library', true);
     $this->permissions->setPermission(0, 'write', true);
 }
Example #22
0
 public static function deleteUser($userID)
 {
     if (empty($userID)) {
         throw new Exception("userID not provided");
     }
     $username = Zotero_Users::getUsername($userID, true);
     $sql = "SELECT LUM_Role.Name FROM LUM_User JOIN LUM_Role USING (RoleID) WHERE UserID=?";
     try {
         $role = Zotero_WWW_DB_2::valueQuery($sql, $userID);
     } catch (Exception $e) {
         Z_Core::logError("WARNING: {$e} -- retrying on primary");
         $role = Zotero_WWW_DB_1::valueQuery($sql, $userID);
     }
     if ($role != 'Deleted') {
         throw new Exception("User '{$username}' does not have role 'Deleted'");
     }
     Zotero_DB::beginTransaction();
     if (Zotero_Groups::getUserOwnedGroups($userID)) {
         throw new Exception("Cannot delete user '{$username}' with owned groups");
     }
     // Remove user from any groups they're a member of
     //
     // This isn't strictly necessary thanks to foreign key cascades,
     // but it removes some extra keyPermissions rows
     $groupIDs = Zotero_Groups::getUserGroups($userID);
     foreach ($groupIDs as $groupID) {
         $group = Zotero_Groups::get($groupID, true);
         $group->removeUser($userID);
     }
     // Remove all data
     Zotero_Users::clearAllData($userID);
     // Remove user publications library
     $libraryID = self::getLibraryIDFromUserID($userID, 'publications');
     if ($libraryID) {
         $shardID = Zotero_Shards::getByLibraryID($libraryID);
         Zotero_DB::query("DELETE FROM shardLibraries WHERE libraryID=?", $libraryID, $shardID);
         Zotero_DB::query("DELETE FROM libraries WHERE libraryID=?", $libraryID);
     }
     // Remove user/library rows
     $libraryID = self::getLibraryIDFromUserID($userID);
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     Zotero_DB::query("DELETE FROM shardLibraries WHERE libraryID=?", $libraryID, $shardID);
     Zotero_DB::query("DELETE FROM libraries WHERE libraryID=?", $libraryID);
     Zotero_DB::commit();
 }
Example #23
0
 public static function getAllAdvanced($userID = false, $params = array(), $permissions = null)
 {
     $buffer = 20;
     $maxTimes = 3;
     $groups = array();
     $start = !empty($params['start']) ? $params['start'] : 0;
     $limit = !empty($params['limit']) ? $params['limit'] + $buffer : false;
     $totalResults = null;
     $times = 0;
     while (true) {
         if ($times > 0) {
             Z_Core::logError('Getting more groups in Zotero_Groups::getAllAdvanced()');
         }
         $sql = "SELECT SQL_CALC_FOUND_ROWS G.groupID, GUO.userID AS ownerUserID FROM groups G\n\t\t\t\t\tJOIN groupUsers GUO ON (G.groupID=GUO.groupID AND GUO.role='owner') ";
         $sqlParams = array();
         if ($userID) {
             $sql .= "JOIN groupUsers GUA ON (G.groupID=GUA.groupID) WHERE GUA.userID=? ";
             $sqlParams[] = $userID;
         }
         $paramSQL = "";
         $includeEmpty = false;
         if (!empty($params['q'])) {
             if (!is_array($params['q'])) {
                 $params['q'] = array($params['q']);
             }
             foreach ($params['q'] as $q) {
                 $field = explode(":", $q);
                 if (sizeOf($field) == 2) {
                     switch ($field[0]) {
                         case 'slug':
                             $includeEmpty = true;
                             break;
                         default:
                             throw new Exception("Cannot search by group field '{$field[0]}'", Z_ERROR_INVALID_GROUP_TYPE);
                     }
                     $paramSQL .= "AND " . $field[0];
                     // If first character is '-', negate
                     $paramSQL .= $field[0][0] == '-' ? '!' : '';
                     $paramSQL .= "=? ";
                     $sqlParams[] = $field[1];
                 } else {
                     $paramSQL .= "AND name LIKE ? ";
                     $sqlParams[] = "%{$q}%";
                 }
             }
         }
         if (!$userID) {
             if ($includeEmpty) {
                 $sql .= "WHERE 1 ";
             } else {
                 // Don't include groups that have never had items
                 $sql .= "JOIN libraries L ON (G.libraryID=L.libraryID)\n\t\t\t\t\t\t\tWHERE L.lastUpdated != '0000-00-00 00:00:00' ";
             }
         }
         $sql .= $paramSQL;
         if (!empty($params['fq'])) {
             if (!is_array($params['fq'])) {
                 $params['fq'] = array($params['fq']);
             }
             foreach ($params['fq'] as $fq) {
                 $facet = explode(":", $fq);
                 if (sizeOf($facet) == 2 && preg_match('/-?GroupType/', $facet[0])) {
                     switch ($facet[1]) {
                         case 'PublicOpen':
                         case 'PublicClosed':
                         case 'Private':
                             break;
                         default:
                             throw new Exception("Invalid group type '{$facet[1]}'", Z_ERROR_INVALID_GROUP_TYPE);
                     }
                     $sql .= "AND type";
                     // If first character is '-', negate
                     $sql .= $facet[0][0] == '-' ? '!' : '';
                     $sql .= "=? ";
                     $sqlParams[] = $facet[1];
                 }
             }
         }
         if (!empty($params['order'])) {
             $order = $params['order'];
             if ($order == 'title') {
                 $order = 'name';
             }
             $sql .= "ORDER BY {$order}";
             if (!empty($params['sort'])) {
                 $sql .= " " . $params['sort'] . " ";
             }
         }
         // Set limit higher than the actual limit, in case some groups are
         // removed during access checks
         //
         // Actual limiting is done below
         if ($limit) {
             $sql .= "LIMIT ?, ?";
             $sqlParams[] = $start;
             $sqlParams[] = $limit;
         }
         $rows = Zotero_DB::query($sql, $sqlParams);
         if (!$rows) {
             break;
         }
         if (!$totalResults) {
             $foundRows = Zotero_DB::valueQuery("SELECT FOUND_ROWS()");
             $totalResults = $foundRows;
         }
         // Include only groups with non-banned owners
         $owners = array();
         foreach ($rows as $row) {
             $owners[] = $row['ownerUserID'];
         }
         $owners = Zotero_Users::getValidUsers($owners);
         $ids = array();
         foreach ($rows as $row) {
             if (!in_array($row['ownerUserID'], $owners)) {
                 $totalResults--;
                 continue;
             }
             $ids[] = $row['groupID'];
         }
         $batchStartPos = sizeOf($groups);
         foreach ($ids as $id) {
             $group = Zotero_Groups::get($id, true);
             $groups[] = $group;
         }
         // Remove groups that can't be accessed
         if ($permissions) {
             for ($i = $batchStartPos; $i < sizeOf($groups); $i++) {
                 $libraryID = (int) $groups[$i]->libraryID;
                 // TEMP: casting shouldn't be necessary
                 if (!$permissions->canAccess($libraryID)) {
                     array_splice($groups, $i, 1);
                     $i--;
                     $totalResults--;
                 }
             }
         }
         $times++;
         if ($times == $maxTimes) {
             Z_Core::logError('Too many queries in Zotero_Groups::getAllAdvanced()');
             break;
         }
         if (empty($params['limit'])) {
             break;
         }
         // If we have enough groups to fill the limit, stop
         if (sizeOf($groups) > $params['limit']) {
             break;
         }
         // If there no more rows, stop
         if ($start + sizeOf($rows) == $foundRows) {
             break;
         }
         // This shouldn't happen
         if ($start + sizeOf($rows) > $foundRows) {
             Z_Core::logError('More rows than $foundRows in Zotero_Groups::getAllAdvanced()');
         }
         $start = $start + sizeOf($rows);
         // Get number we still need plus the buffer or all remaining, whichever is lower
         $limit = min($params['limit'] - sizeOf($groups) + $buffer, $foundRows - $start);
     }
     // TODO: generate previous start value
     if (!$groups) {
         return array('groups' => array(), 'totalResults' => 0);
     }
     // Fake limiting -- we can't just use SQL limit because
     // some groups might be inaccessible
     if (!empty($params['limit'])) {
         $groups = array_slice($groups, 0, $params['limit']);
     }
     $results = array('groups' => $groups, 'totalResults' => $totalResults);
     return $results;
 }
Example #24
0
 /**
  * Make sure we have a valid session
  */
 private function sessionCheck()
 {
     if (empty($_REQUEST['sessionid'])) {
         $this->error(403, 'NO_SESSION_ID', "Session ID not provided");
     }
     if (!preg_match('/^[a-f0-9]{32}$/', $_REQUEST['sessionid'])) {
         $this->error($this->apiVersion >= 9 ? 403 : 500, 'INVALID_SESSION_ID', "Invalid session ID");
     }
     $sessionID = $_REQUEST['sessionid'];
     $session = Z_Core::$MC->get("syncSession_{$sessionID}");
     $userID = $session ? $session['userID'] : null;
     // TEMP: can switch to just $session
     $ipAddress = isset($session['ipAddress']) ? $session['ipAddress'] : null;
     if (!$userID) {
         $sql = "SELECT userid, (UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(timestamp)) AS age,\n\t\t\t\t\tINET_NTOA(ipAddress) AS ipAddress FROM sessions WHERE sessionID=?";
         $session = Zotero_DB::rowQuery($sql, $sessionID);
         if (!$session) {
             $this->error($this->apiVersion >= 9 ? 403 : 500, 'INVALID_SESSION_ID', "Invalid session ID");
         }
         if ($session['age'] > $this->sessionLifetime) {
             $this->error($this->apiVersion >= 9 ? 403 : 500, 'SESSION_TIMED_OUT', "Session timed out");
         }
         $userID = $session['userid'];
         $ipAddress = $session['ipAddress'];
     }
     $updated = Z_Core::$MC->set("syncSession_{$sessionID}", array('sessionID' => $sessionID, 'userID' => $userID, 'ipAddress' => $ipAddress), $this->sessionLifetime - 1200);
     // Every 20 minutes, update the timestamp in the DB
     if (!Z_Core::$MC->get("syncSession_" . $sessionID . "_dbUpdated")) {
         $sql = "UPDATE sessions SET timestamp=NOW() WHERE sessionID=?";
         Zotero_DB::query($sql, $sessionID);
         Z_Core::$MC->set("syncSession_" . $sessionID . "_dbUpdated", true, 1200);
     }
     $this->sessionID = $sessionID;
     $this->userID = $userID;
     $this->userLibraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     $this->ipAddress = $ipAddress;
 }
Example #25
0
	public function toResponseJSON($requestParams=[], Zotero_Permissions $permissions, $sharedData=null) {
		$t = microtime(true);
		
		if (!$this->loaded['primaryData']) {
			$this->loadPrimaryData();
		}
		if (!$this->loaded['itemData']) {
			$this->loadItemData();
		}
		
		// Uncached stuff or parts of the cache key
		$version = $this->version;
		$parent = $this->getSource();
		$isRegularItem = !$parent && $this->isRegularItem();
		$downloadDetails = $permissions->canAccess($this->libraryID, 'files')
								? Zotero_Storage::getDownloadDetails($this)
								: false;
		if ($isRegularItem) {
			$numChildren = $permissions->canAccess($this->libraryID, 'notes')
								? $this->numChildren()
								: $this->numAttachments();
		}
		$libraryType = Zotero_Libraries::getType($this->libraryID);
		
		// Any query parameters that have an effect on the output
		// need to be added here
		$allowedParams = [
			'include',
			'style',
			'css',
			'linkwrap'
		];
		$cachedParams = Z_Array::filterKeys($requestParams, $allowedParams);
		
		$cacheVersion = 1;
		$cacheKey = "jsonEntry_" . $this->libraryID . "/" . $this->id . "_"
			. md5(
				$version
				. json_encode($cachedParams)
				. ($downloadDetails ? 'hasFile' : '')
				// For groups, include the group WWW URL, which can change
				. ($libraryType == 'group' ? Zotero_URI::getItemURI($this, true) : '')
			)
			. "_" . $requestParams['v']
			// For code-based changes
			. "_" . $cacheVersion
			// For data-based changes
			. (isset(Z_CONFIG::$CACHE_VERSION_RESPONSE_JSON_ITEM)
				? "_" . Z_CONFIG::$CACHE_VERSION_RESPONSE_JSON_ITEM
				: "")
			// If there's bib content, include the bib cache version
			. ((in_array('bib', $requestParams['include'])
					&& isset(Z_CONFIG::$CACHE_VERSION_BIB))
				? "_" . Z_CONFIG::$CACHE_VERSION_BIB
				: "");
		
		$cached = Z_Core::$MC->get($cacheKey);
		if (false && $cached) {
			// Make sure numChildren reflects the current permissions
			if ($isRegularItem) {
				$json = json_decode($cached);
				$json['numChildren'] = $numChildren;
				$cached = json_encode($json);
			}
			
			//StatsD::timing("api.items.itemToResponseJSON.cached", (microtime(true) - $t) * 1000);
			//StatsD::increment("memcached.items.itemToResponseJSON.hit");
			
			// Skip the cache every 10 times for now, to ensure cache sanity
			if (!Z_Core::probability(10)) {
				return $cached;
			}
		}
		
		
		$json = [
			'key' => $this->key,
			'version' => $version,
			'library' => Zotero_Libraries::toJSON($this->libraryID)
		];
		
		$json['links'] = [
			'self' => [
				'href' => Zotero_API::getItemURI($this),
				'type' => 'application/json'
			],
			'alternate' => [
				'href' => Zotero_URI::getItemURI($this, true),
				'type' => 'text/html'
			]
		];
		
		if ($parent) {
			$parentItem = Zotero_Items::get($this->libraryID, $parent);
			$json['links']['up'] = [
				'href' => Zotero_API::getItemURI($parentItem),
				'type' => 'application/json'
			];
		}
		
		// If appropriate permissions and the file is stored in ZFS, get file request link
		if ($downloadDetails) {
			$details = $downloadDetails;
			$type = $this->attachmentMIMEType;
			if ($type) {
				$json['links']['enclosure'] = [
					'type' => $type
				];
			}
			$json['links']['enclosure']['href'] = $details['url'];
			if (!empty($details['filename'])) {
				$json['links']['enclosure']['title'] = $details['filename'];
			}
			if (isset($details['size'])) {
				$json['links']['enclosure']['length'] = $details['size'];
			}
		}
		
		// 'meta'
		$json['meta'] = new stdClass;
		
		if (Zotero_Libraries::getType($this->libraryID) == 'group') {
			$createdByUserID = $this->createdByUserID;
			$lastModifiedByUserID = $this->lastModifiedByUserID;
			
			if ($createdByUserID) {
				$json['meta']->createdByUser = Zotero_Users::toJSON($createdByUserID);
			}
			
			if ($lastModifiedByUserID && $lastModifiedByUserID != $createdByUserID) {
				$json['meta']->lastModifiedByUser = Zotero_Users::toJSON($lastModifiedByUserID);
			}
		}
		
		if ($isRegularItem) {
			$val = $this->getCreatorSummary();
			if ($val !== '') {
				$json['meta']->creatorSummary = $val;
			}
			
			$val = $this->getField('date', true, true, true);
			if ($val !== '') {
				$sqlDate = Zotero_Date::multipartToSQL($val);
				if (substr($sqlDate, 0, 4) !== '0000') {
					$json['meta']->parsedDate = Zotero_Date::sqlToISO8601($sqlDate);
				}
			}
			
			$json['meta']->numChildren = $numChildren;
		}
		
		// 'include'
		$include = $requestParams['include'];
		
		foreach ($include as $type) {
			if ($type == 'html') {
				$json[$type] = trim($this->toHTML());
			}
			else if ($type == 'citation') {
				if (isset($sharedData[$type][$this->libraryID . "/" . $this->key])) {
					$html = $sharedData[$type][$this->libraryID . "/" . $this->key];
				}
				else {
					if ($sharedData !== null) {
						//error_log("Citation not found in sharedData -- retrieving individually");
					}
					$html = Zotero_Cite::getCitationFromCiteServer($this, $requestParams);
				}
				$json[$type] = $html;
			}
			else if ($type == 'bib') {
				if (isset($sharedData[$type][$this->libraryID . "/" . $this->key])) {
					$html = $sharedData[$type][$this->libraryID . "/" . $this->key];
				}
				else {
					if ($sharedData !== null) {
						//error_log("Bibliography not found in sharedData -- retrieving individually");
					}
					$html = Zotero_Cite::getBibliographyFromCitationServer([$this], $requestParams);
					
					// Strip prolog
					$html = preg_replace('/^<\?xml.+\n/', "", $html);
					$html = trim($html);
				}
				$json[$type] = $html;
			}
			else if ($type == 'data') {
				$json[$type] = $this->toJSON(true, $requestParams, true);
			}
			else if ($type == 'csljson') {
				$json[$type] = $this->toCSLItem();
			}
			else if (in_array($type, Zotero_Translate::$exportFormats)) {
				$export = Zotero_Translate::doExport([$this], $type);
				$json[$type] = $export['body'];
				unset($export);
			}
		}
		

		// TEMP
		if ($cached) {
			$uncached = Zotero_Utilities::formatJSON($json);
			if ($cached != $uncached) {
				error_log("Cached JSON item entry does not match");
				error_log("  Cached: " . $cached);
				error_log("Uncached: " . $uncached);
				
				//Z_Core::$MC->set($cacheKey, $uncached, 3600); // 1 hour for now
			}
		}
		else {
			/*Z_Core::$MC->set($cacheKey, $xmlstr, 3600); // 1 hour for now
			StatsD::timing("api.items.itemToAtom.uncached", (microtime(true) - $t) * 1000);
			StatsD::increment("memcached.items.itemToAtom.miss");*/
		}
		
		return $json;
	}
Example #26
0
 /**
  * Converts a Zotero_Item object to a SimpleXMLElement Atom object
  *
  * @param	object				$item		Zotero_Item object
  * @param	string				$content
  * @return	SimpleXMLElement					Item data as SimpleXML element
  */
 public static function convertItemToAtom(Zotero_Item $item, $queryParams, $apiVersion = null, $permissions = null, $sharedData = null)
 {
     $content = $queryParams['content'];
     $contentIsHTML = sizeOf($content) == 1 && $content[0] == 'html';
     $contentParamString = urlencode(implode(',', $content));
     $style = $queryParams['style'];
     $entry = '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>';
     $xml = new SimpleXMLElement($entry);
     $title = $item->getDisplayTitle(true);
     $title = $title ? $title : '[Untitled]';
     $xml->title = $title;
     $author = $xml->addChild('author');
     $createdByUserID = null;
     switch (Zotero_Libraries::getType($item->libraryID)) {
         case 'group':
             $createdByUserID = $item->createdByUserID;
             break;
     }
     if ($createdByUserID) {
         $author->name = Zotero_Users::getUsername($createdByUserID);
         $author->uri = Zotero_URI::getUserURI($createdByUserID);
     } else {
         $author->name = Zotero_Libraries::getName($item->libraryID);
         $author->uri = Zotero_URI::getLibraryURI($item->libraryID);
     }
     $id = Zotero_URI::getItemURI($item);
     /*if (!$contentIsHTML) {
     			$id .= "?content=$content";
     		}*/
     $xml->id = $id;
     $xml->published = Zotero_Date::sqlToISO8601($item->getField('dateAdded'));
     $xml->updated = Zotero_Date::sqlToISO8601($item->getField('dateModified'));
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $href = Zotero_Atom::getItemURI($item);
     if (!$contentIsHTML) {
         $href .= "?content={$contentParamString}";
     }
     $link['href'] = $href;
     $parent = $item->getSource();
     if ($parent) {
         // TODO: handle group items?
         $parentItem = Zotero_Items::get($item->libraryID, $parent);
         $link = $xml->addChild("link");
         $link['rel'] = "up";
         $link['type'] = "application/atom+xml";
         $href = Zotero_Atom::getItemURI($parentItem);
         if (!$contentIsHTML) {
             $href .= "?content={$contentParamString}";
         }
         $link['href'] = $href;
     }
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getItemURI($item);
     // If appropriate permissions and the file is stored in ZFS, get file request link
     if ($permissions && $permissions->canAccess($item->libraryID, 'files')) {
         $details = Zotero_S3::getDownloadDetails($item);
         if ($details) {
             $link = $xml->addChild('link');
             $link['rel'] = 'enclosure';
             $type = $item->attachmentMIMEType;
             if ($type) {
                 $link['type'] = $type;
             }
             $link['href'] = $details['url'];
             if (!empty($details['filename'])) {
                 $link['title'] = $details['filename'];
             }
             if (!empty($details['size'])) {
                 $link['length'] = $details['size'];
             }
         }
     }
     $xml->addChild('zapi:key', $item->key, Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:itemType', Zotero_ItemTypes::getName($item->itemTypeID), Zotero_Atom::$nsZoteroAPI);
     if ($item->isRegularItem()) {
         $val = $item->creatorSummary;
         if ($val !== '') {
             $xml->addChild('zapi:creatorSummary', htmlspecialchars($val), Zotero_Atom::$nsZoteroAPI);
         }
         $val = substr($item->getField('date', true, true, true), 0, 4);
         if ($val !== '' && $val !== '0000') {
             $xml->addChild('zapi:year', $val, Zotero_Atom::$nsZoteroAPI);
         }
     }
     if (!$parent && $item->isRegularItem()) {
         if ($permissions && !$permissions->canAccess($item->libraryID, 'notes')) {
             $numChildren = $item->numAttachments();
         } else {
             $numChildren = $item->numChildren();
         }
         $xml->addChild('zapi:numChildren', $numChildren, Zotero_Atom::$nsZoteroAPI);
     }
     $xml->addChild('zapi:numTags', $item->numTags(), Zotero_Atom::$nsZoteroAPI);
     $xml->content = '';
     //
     // DOM XML from here on out
     //
     $contentNode = dom_import_simplexml($xml->content);
     $domDoc = $contentNode->ownerDocument;
     $multiFormat = sizeOf($content) > 1;
     // Create a root XML document for multi-format responses
     if ($multiFormat) {
         $contentNode->setAttribute('type', 'application/xml');
         /*$multicontent = $domDoc->createElementNS(
         			Zotero_Atom::$nsZoteroAPI, 'multicontent'
         		);
         		$contentNode->appendChild($multicontent);*/
     }
     foreach ($content as $type) {
         // Set the target to either the main <content>
         // or a <multicontent> <content>
         if (!$multiFormat) {
             $target = $contentNode;
         } else {
             $target = $domDoc->createElementNS(Zotero_Atom::$nsZoteroAPI, 'subcontent');
             $contentNode->appendChild($target);
         }
         $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:type", $type);
         if ($type == 'html') {
             if (!$multiFormat) {
                 $target->setAttribute('type', 'xhtml');
             }
             $div = $domDoc->createElement('div');
             $div->setAttribute('xmlns', Zotero_Atom::$nsXHTML);
             $target->appendChild($div);
             $html = $item->toHTML(true);
             $subNode = dom_import_simplexml($html);
             $importedNode = $domDoc->importNode($subNode, true);
             $div->appendChild($importedNode);
         } else {
             if ($type == 'citation') {
                 if (!$multiFormat) {
                     $target->setAttribute('type', 'xhtml');
                 }
                 if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                     $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                 } else {
                     if ($sharedData !== null) {
                         error_log("Citation not found in sharedData -- retrieving individually");
                     }
                     $html = Zotero_Cite::getCitationFromCiteServer($item, $style);
                 }
                 $html = new SimpleXMLElement($html);
                 $html['xmlns'] = Zotero_Atom::$nsXHTML;
                 $subNode = dom_import_simplexml($html);
                 $importedNode = $domDoc->importNode($subNode, true);
                 $target->appendChild($importedNode);
             } else {
                 if ($type == 'bib') {
                     if (!$multiFormat) {
                         $target->setAttribute('type', 'xhtml');
                     }
                     if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                         $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                     } else {
                         if ($sharedData !== null) {
                             error_log("Bibliography not found in sharedData -- retrieving individually");
                         }
                         $html = Zotero_Cite::getBibliographyFromCitationServer(array($item), $style);
                     }
                     $html = new SimpleXMLElement($html);
                     $html['xmlns'] = Zotero_Atom::$nsXHTML;
                     $subNode = dom_import_simplexml($html);
                     $importedNode = $domDoc->importNode($subNode, true);
                     $target->appendChild($importedNode);
                 } else {
                     if ($type == 'json') {
                         $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:etag", $item->etag);
                         $textNode = $domDoc->createTextNode($item->toJSON(false, $queryParams['pprint'], true));
                         $target->appendChild($textNode);
                     } else {
                         if ($type == 'csljson') {
                             $arr = $item->toCSLItem();
                             $mask = JSON_HEX_TAG | JSON_HEX_AMP;
                             if ($queryParams['pprint']) {
                                 $json = Zotero_Utilities::json_encode_pretty($arr, $mask);
                             } else {
                                 $json = json_encode($arr, $mask);
                             }
                             // Until JSON_UNESCAPED_SLASHES is available
                             $json = str_replace('\\/', '/', $json);
                             $textNode = $domDoc->createTextNode($json);
                             $target->appendChild($textNode);
                         } else {
                             if ($type == 'full') {
                                 if (!$multiFormat) {
                                     $target->setAttribute('type', 'xhtml');
                                 }
                                 $fullXML = Zotero_Items::convertItemToXML($item, array(), $apiVersion);
                                 $fullXML->addAttribute("xmlns", Zotero_Atom::$nsZoteroTransfer);
                                 $subNode = dom_import_simplexml($fullXML);
                                 $importedNode = $domDoc->importNode($subNode, true);
                                 $target->appendChild($importedNode);
                             } else {
                                 if (in_array($type, Zotero_Translate::$exportFormats)) {
                                     $export = Zotero_Translate::doExport(array($item), $type);
                                     $target->setAttribute('type', $export['mimeType']);
                                     // Insert XML into document
                                     if (preg_match('/\\+xml$/', $export['mimeType'])) {
                                         // Strip prolog
                                         $body = preg_replace('/^<\\?xml.+\\n/', "", $export['body']);
                                         $subNode = $domDoc->createDocumentFragment();
                                         $subNode->appendXML($body);
                                         $target->appendChild($subNode);
                                     } else {
                                         $textNode = $domDoc->createTextNode($export['body']);
                                         $target->appendChild($textNode);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return $xml;
 }
Example #27
0
 private static function getURIObject($objectURI, $type)
 {
     $Types = ucwords($type) . 's';
     $types = strtolower($Types);
     $libraryType = null;
     $baseURI = self::getBaseURI();
     // If not found, try global URI
     if (strpos($objectURI, $baseURI) !== 0) {
         throw new Exception("Invalid base URI '{$objectURI}'");
     }
     $objectURI = substr($objectURI, strlen($baseURI));
     $typeRE = "/^(users|groups)\\/([0-9]+)(?:\\/|\$)/";
     if (!preg_match($typeRE, $objectURI, $matches)) {
         throw new Exception("Invalid library URI '{$objectURI}'");
     }
     $libraryType = substr($matches[1], 0, -1);
     $id = $matches[2];
     $objectURI = preg_replace($typeRE, '', $objectURI);
     if ($libraryType == 'user') {
         if (!Zotero_Users::exists($id)) {
             return false;
         }
         $libraryID = Zotero_Users::getLibraryIDFromUserID($id);
     } else {
         if ($libraryType == 'group') {
             if (!Zotero_Groups::get($id)) {
                 return false;
             }
             $libraryID = Zotero_Groups::getLibraryIDFromGroupID($id);
         } else {
             throw new Exception("Invalid library type {$libraryType}");
         }
     }
     if ($type === 'library') {
         return $libraryID;
     } else {
         // TODO: objectID-based URI?
         if (!preg_match($types . "\\/([A-Z0-9]{8})", $objectURI, $matches)) {
             throw new Exception("Invalid object URI '{$objectURI}'");
         }
         $objectKey = $matches[1];
         return call_user_func(array("Zotero_{$Types}", "getByLibraryAndKey"), $libraryID, $objectKey);
     }
 }
Example #28
0
 public function testAuthenticate()
 {
     $this->assertEquals(Zotero_Users::authenticate('password', array('username' => 'testuser', 'password' => 'letmein')), 1);
     $this->assertEquals(Zotero_Users::authenticate('password', array('username' => 'testuser', 'password' => 'letmein2')), false);
 }
Example #29
0
 public static function getLibraryURI($libraryID)
 {
     $libraryType = Zotero_Libraries::getType($libraryID);
     switch ($libraryType) {
         case 'user':
             $id = Zotero_Users::getUserIDFromLibraryID($libraryID);
             return self::getBaseURI() . "users/{$id}";
         case 'publications':
             $id = Zotero_Users::getUserIDFromLibraryID($libraryID);
             return self::getBaseURI() . "users/{$id}/publications";
         case 'group':
             $id = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
             return self::getBaseURI() . "groups/{$id}";
         default:
             throw new Exception("Invalid library type '{$libraryType}'");
     }
 }
Example #30
0
 private function logGroupLibraryRemoval()
 {
     $users = $this->getUsers();
     $usersByShard = array();
     foreach ($users as $userID) {
         $shardID = Zotero_Shards::getByUserID($userID);
         if (!isset($usersByShard[$shardID])) {
             $usersByShard[$shardID] = array();
         }
         $usersByShard[$shardID][] = $userID;
     }
     foreach ($usersByShard as $shardID => $userIDs) {
         // Add to delete log for all group members
         $sql = "REPLACE INTO syncDeleteLogIDs (libraryID, objectType, id) VALUES ";
         $params = array();
         $sets = array();
         foreach ($userIDs as $userID) {
             $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
             $sets[] = "(?,?,?)";
             $params = array_merge($params, array($libraryID, 'group', $this->id));
         }
         $sql .= implode(",", $sets);
         Zotero_DB::query($sql, $params, $shardID);
     }
 }