www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

uri.js (12661B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2009 Center for History and New Media
      5                      George Mason University, Fairfax, Virginia, USA
      6                      http://zotero.org
      7     
      8     This file is part of Zotero.
      9     
     10     Zotero is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU Affero General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14     
     15     Zotero is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU Affero General Public License for more details.
     19     
     20     You should have received a copy of the GNU Affero General Public License
     21     along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     22     
     23     ***** END LICENSE BLOCK *****
     24 */
     25 
     26 
     27 Zotero.URI = new function () {
     28 	Zotero.defineProperty(this, 'defaultPrefix', {
     29 		value: 'http://zotero.org/'
     30 	});
     31 	
     32 	// This should match all possible URIs. Match groups are as follows:
     33 	// 1: users|groups
     34 	// 2: local/|NULL
     35 	// 3: userID|groupID|localUserKey
     36 	// 4: publications|feeds/libraryID|NULL
     37 	// 5: items|collections|NULL
     38 	// 6: itemKey|collectionKey|NULL
     39 	var uriPartsRe = new RegExp(
     40 		'^' + Zotero.Utilities.quotemeta(this.defaultPrefix)
     41 		+ '(users|groups)/(local/)?(\\w+)(?:/(publications|feeds/\\w+))?'
     42 		+ '(?:/(items|collections)/(\\w+))?'
     43 	);
     44 	
     45 	/**
     46 	 * Get a URI with the user's local key, if there is one
     47 	 *
     48 	 * @return	{String|False}		e.g., 'http://zotero.org/users/local/v3aG8nQf'
     49 	 */
     50 	this.getLocalUserURI = function () {
     51 		return this.defaultPrefix + "users/local/" + Zotero.Users.getLocalUserKey();
     52 	}
     53 	
     54 	
     55 	/**
     56 	 * Get a URI for the user, creating a local user key if necessary
     57 	 *
     58 	 * @return	{String}
     59 	 */
     60 	this.getCurrentUserURI = function () {
     61 		var userID = Zotero.Users.getCurrentUserID();
     62 		if (userID) {
     63 			return this.defaultPrefix + "users/" + userID;
     64 		}
     65 		
     66 		return this.getLocalUserURI();
     67 	}
     68 	
     69 	
     70 	this.getCurrentUserLibraryURI = function () {
     71 		var userID = Zotero.Users.getCurrentUserID();
     72 		if (!userID) {
     73 			return false;
     74 		}
     75 		return this.getCurrentUserURI() + "/items";
     76 	}
     77 	
     78 	
     79 	this.getLibraryURI = function (libraryID) {
     80 		return this.defaultPrefix + this.getLibraryPath(libraryID);
     81 	}
     82 	
     83 	
     84 	/**
     85 	 * Get path portion of library URI (e.g., users/6 or groups/1)
     86 	 */
     87 	this.getLibraryPath = function (libraryID) {
     88 		var libraryType = Zotero.Libraries.get(libraryID).libraryType;
     89 		
     90 		switch (libraryType) {
     91 			case 'user':
     92 				var id = Zotero.Users.getCurrentUserID();
     93 				if (!id) {
     94 					id = 'local/' + Zotero.Users.getLocalUserKey();
     95 				}
     96 				
     97 				if (libraryType == 'publications') {
     98 					return "users/" + id + "/" + libraryType;
     99 				}
    100 				
    101 				break;
    102 			
    103 			case 'feed':
    104 				// Since feeds are not currently synced, generate a local URI
    105 				return "users/local/" + Zotero.Users.getLocalUserKey() + "/feeds/" + libraryID;
    106 			
    107 			case 'group':
    108 				var id = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
    109 				break;
    110 			
    111 			default:
    112 				throw new Error(`Unsupported library type '${libraryType}' for library ${libraryID}`);
    113 		}
    114 		
    115 		return libraryType + "s/" + id;
    116 	}
    117 	
    118 	
    119 	/**
    120 	 * Get library from path (e.g., users/6 or groups/1)
    121 	 *
    122 	 * @return {Zotero.Library|false}
    123 	 */
    124 	this.getPathLibrary = function (path) {
    125 		let matches = path.match(/^\/\/?users\/(\d+)/);
    126 		if (matches) {
    127 			let userID = matches[1];
    128 			let currentUserID = Zotero.Users.getCurrentUserID();
    129 			if (userID != currentUserID) {
    130 				Zotero.debug("User ID from streaming server doesn't match current id! "
    131 					+ `(${userID} != ${currentUserID})`);
    132 				return false;
    133 			}
    134 			return Zotero.Libraries.userLibrary;
    135 		}
    136 		matches = path.match(/^\/groups\/(\d+)/);
    137 		if (matches) {
    138 			let groupID = matches[1];
    139 			return Zotero.Groups.get(groupID);
    140 		}
    141 	}
    142 	
    143 	
    144 	/**
    145 	 * Return URI of item, which might be a local URI if user hasn't synced
    146 	 */
    147 	this.getItemURI = function (item) {
    148 		return this._getObjectURI(item);
    149 	}
    150 	
    151 	
    152 	/**
    153 	 * Get path portion of item URI (e.g., users/6/items/ABCD1234 or groups/1/items/ABCD1234)
    154 	 */
    155 	this.getItemPath = function (item) {
    156 		return this._getObjectPath(item);
    157 	}
    158 	
    159 	
    160 	this.getFeedItemURI = function(feedItem) {
    161 		return this.getItemURI(feedItem);
    162 	}
    163 	
    164 	this.getFeedItemPath = function(feedItem) {
    165 		return this.getItemPath(feedItem);
    166 	}
    167 	
    168 	/**
    169 	 * Return URI of collection, which might be a local URI if user hasn't synced
    170 	 */
    171 	this.getCollectionURI = function (collection) {
    172 		return this._getObjectURI(collection);
    173 	}
    174 	
    175 	
    176 	/**
    177 	 * Get path portion of collection URI (e.g., users/6/collections/ABCD1234 or groups/1/collections/ABCD1234)
    178 	 */
    179 	this.getCollectionPath = function (collection) {
    180 		return this._getObjectPath(collection);
    181 	}
    182 	
    183 	this.getFeedURI = function(feed) {
    184 		return this.getLibraryURI(feed);
    185 	}
    186 	
    187 	this.getFeedPath = function(feed) {
    188 		return this.getLibraryPath(feed);
    189 	}
    190 	
    191 	
    192 	this.getGroupsURL = function () {
    193 		return ZOTERO_CONFIG.WWW_BASE_URL + "groups";
    194 	}
    195 	
    196 	
    197 	/**
    198 	 * @param	{Zotero.Group}		group
    199 	 * @return	{String}
    200 	 */
    201 	this.getGroupURI = function (group, webRoot) {
    202 		var uri = this._getObjectURI(group);
    203 		if (webRoot) {
    204 			uri = uri.replace(ZOTERO_CONFIG.BASE_URI, ZOTERO_CONFIG.WWW_BASE_URL);
    205 		}
    206 		return uri;
    207 	}
    208 	
    209 	this._getObjectPath = function(obj) {
    210 		let path = this.getLibraryPath(obj.libraryID);
    211 		if (obj instanceof Zotero.Library) {
    212 			return path;
    213 		}
    214 		
    215 		if (obj instanceof Zotero.Item) {
    216 			return path + '/items/' + obj.key;
    217 		}
    218 		
    219 		if (obj instanceof Zotero.Collection) {
    220 			return path + '/collections/' + obj.key;
    221 		}
    222 		
    223 		throw new Error("Unsupported object type '" + obj._objectType + "'");
    224 	}
    225 	
    226 	this._getObjectURI = function(obj) {
    227 		return this.defaultPrefix + this._getObjectPath(obj);
    228 	}
    229 	
    230 	/**
    231 	 * Convert an item URI into an item
    232 	 *
    233 	 * @param	{String}				itemURI
    234 	 * @return {Promise<Zotero.Item|false>}
    235 	 */
    236 	this.getURIItem = Zotero.Promise.method(function (itemURI) {
    237 		var obj = this._getURIObject(itemURI, 'item');
    238 		if (!obj) return false;
    239 		return Zotero.Items.getByLibraryAndKeyAsync(obj.libraryID, obj.key);
    240 	});
    241 	
    242 	
    243 	/**
    244 	 * @param {String} itemURI
    245 	 * @return {Object|FALSE} - Object with 'libraryID' and 'key', or FALSE if item not found
    246 	 */
    247 	this.getURIItemLibraryKey = function (itemURI) {
    248 		return this._getURIObject(itemURI, 'item');
    249 	}
    250 	
    251 	
    252 	/**
    253 	 * Convert an item URI into a libraryID and key from the database, without relying on global state
    254 	 *
    255 	 * Note that while the URI must point to a valid library, the item doesn't need to exist
    256 	 */
    257 	this.getURIItemLibraryKeyFromDB = function (itemURI) {
    258 		return this._getURIObjectLibraryKeyFromDB(itemURI, 'item');
    259 	}
    260 	
    261 	
    262 	/**
    263 	 * @param {String} itemURI
    264 	 * @return {Integer|FALSE} - itemID of matching item, or FALSE if none
    265 	 */
    266 	this.getURIItemID = function (itemURI) {
    267 		var obj = this._getURIObject(itemURI, 'item');
    268 		if (!obj) return false;
    269 		return Zotero.Items.getIDFromLibraryAndKey(obj.libraryID, obj.key);
    270 	}
    271 	
    272 	
    273 	/**
    274 	 * Convert a collection URI into a collection
    275 	 *
    276 	 * @param	{String}				collectionURI
    277 	 * @param	{Zotero.Collection|FALSE}
    278 	 * @return {Promise<Zotero.Collection|false>}
    279 	 */
    280 	this.getURICollection = Zotero.Promise.method(function (collectionURI) {
    281 		var obj = this._getURIObject(collectionURI, 'collection');
    282 		if (!obj) return false;
    283 		return Zotero.Collections.getByLibraryAndKeyAsync(obj.libraryID, obj.key);
    284 	});
    285 	
    286 	
    287 	/**
    288 	 * @param {String} collectionURI
    289 	 * @return {Object|FALSE} - Object with 'libraryID' and 'key', or FALSE if item not found
    290 	 */
    291 	this.getURICollectionLibraryKey = function (collectionURI) {
    292 		return this._getURIObject(collectionURI, 'collection');;
    293 	}
    294 	
    295 	
    296 	/**
    297 	 * @param {String} collectionURI
    298 	 * @return {Integer|FALSE} - collectionID of matching collection, or FALSE if none
    299 	 */
    300 	this.getURICollectionID = function (collectionURI) {
    301 		var obj = this._getURIObject(collectionURI, 'collection');
    302 		if (!obj) return false;
    303 		return Zotero.Collections.getIDFromLibraryAndKey(obj.libraryID, obj.key);
    304 	}
    305 	
    306 	
    307 	/**
    308 	 * Convert a library URI into a libraryID
    309 	 *
    310 	 * @param	{String}				libraryURI
    311 	 * @return {Integer|FALSE} - libraryID, or FALSE if no matching library
    312 	 */
    313 	this.getURILibrary = function (libraryURI) {
    314 		let library = this._getURIObjectLibrary(libraryURI);
    315 		return library ? library.id : false;
    316 	}
    317 
    318 
    319 	this.getURIFeed = function (feedURI) {
    320 		return this._getURIObjectLibrary(feedURI, 'feed');
    321 	}
    322 	
    323 	
    324 	/**
    325 	 * Convert an object URI into an object containing libraryID and key
    326 	 *
    327 	 * @param {String} objectURI
    328 	 * @param {String} [type] Object type to expect
    329 	 * @return {Object|FALSE} - An object containing libraryID, objectType and
    330 	 *   key. Key and objectType may not be present if the URI references a
    331 	 *   library itself
    332 	 */
    333 	this._getURIObject = function (objectURI, type) { 
    334 		let uri = objectURI.replace(/\/+$/, ''); // Drop trailing /
    335 		let uriParts = uri.match(uriPartsRe);
    336 		
    337 		if (!uriParts) {
    338 			throw new Error("Could not parse object URI " + objectURI);
    339 		}
    340 		
    341 		let library = this._getURIObjectLibrary(objectURI);
    342 		if (!library) return false;
    343 		
    344 		let retObj = {libraryID: library.libraryID};
    345 		if (!uriParts[5]) {
    346 			// References the library itself
    347 			return retObj;
    348 		}
    349 		
    350 		retObj.objectType = uriParts[5] == 'items' ? 'item' : 'collection';
    351 		retObj.key = uriParts[6];
    352 		
    353 		if (type && type != retObj.objectType) return false;
    354 		
    355 		return retObj;
    356 	};
    357 	
    358 	
    359 	/**
    360 	 * Convert an object URI into a Zotero.Library that the object is in
    361 	 *
    362 	 * @param {String}	objectURI
    363 	 * @return {Zotero.Library|FALSE} - An object referenced by the URI
    364 	 */
    365 	this._getURIObjectLibrary = function (objectURI) {
    366 		let uri = objectURI.replace(/\/+$/, ''); // Drop trailing "/"
    367 		let uriParts = uri.match(uriPartsRe);
    368 		
    369 		if (!uriParts) {
    370 			throw new Error("Could not parse object URI " + objectURI);
    371 		}
    372 		
    373 		let library;
    374 		if (uriParts[1] == 'users') {
    375 			let type = uriParts[4];
    376 			if (!type) {
    377 				// Handles local and synced libraries
    378 				library = Zotero.Libraries.get(Zotero.Libraries.userLibraryID);
    379 			} else {
    380 				let feedID = type.split('/')[1];
    381 				library = Zotero.Libraries.get(feedID);
    382 			}
    383 		} else {
    384 			// Group libraries
    385 			library = Zotero.Groups.get(uriParts[3]);
    386 		}
    387 		
    388 		if (!library) {
    389 			Zotero.debug("Could not find a library for URI " + objectURI, 2, true);
    390 			return false;
    391 		}
    392 		
    393 		return library;
    394 	}
    395 	
    396 	
    397 	/**
    398 	 * Convert an object URI into a libraryID from the database, without relying on global state
    399 	 *
    400 	 * @param {String}	objectURI
    401 	 * @return {Promise<Integer|FALSE>} - A promise for either a libraryID or FALSE if a matching
    402 	 *     library couldn't be found
    403 	 */
    404 	this._getURIObjectLibraryID = Zotero.Promise.coroutine(function* (objectURI) {
    405 		let uri = objectURI.replace(/\/+$/, ''); // Drop trailing "/"
    406 		let uriParts = uri.match(uriPartsRe);
    407 		
    408 		let libraryID;
    409 		if (uriParts[1] == 'users') {
    410 			let type = uriParts[4];
    411 			// Personal library
    412 			if (!type || type == 'publications') {
    413 				libraryID = yield Zotero.DB.valueQueryAsync(
    414 					"SELECT libraryID FROM libraries WHERE type='user'"
    415 				);
    416 			}
    417 			// Feed libraries
    418 			else {
    419 				libraryID = type.split('/')[1];
    420 			}
    421 		}
    422 		// Group libraries
    423 		else {
    424 			libraryID = yield Zotero.DB.valueQueryAsync(
    425 				"SELECT libraryID FROM groups WHERE groupID=?", uriParts[3]
    426 			);
    427 		}
    428 		
    429 		if (!libraryID) {
    430 			Zotero.debug("Could not find a library for URI " + objectURI, 2, true);
    431 			return false;
    432 		}
    433 		
    434 		return libraryID;
    435 	});
    436 	
    437 	
    438 	
    439 	/**
    440 	 * Convert an object URI into a libraryID and key from the database, without relying on global state
    441 	 *
    442 	 * Note that while the URI must point to a valid library, the object doesn't need to exist
    443 	 *
    444 	 * @param {String} objectURI - Object URI
    445 	 * @param {String} type - Object type
    446 	 * @return {Promise<Object|FALSE>} - A promise for an object with 'objectType', 'libraryID', 'key'
    447 	 *     or FALSE if library didn't exist
    448 	 */
    449 	this._getURIObjectLibraryKeyFromDB = Zotero.Promise.coroutine(function* (objectURI, type) {
    450 		let uri = objectURI.replace(/\/+$/, ''); // Drop trailing /
    451 		let uriParts = uri.match(uriPartsRe);
    452 		
    453 		if (!uriParts) {
    454 			throw new Error("Could not parse object URI " + uri);
    455 		}
    456 		
    457 		let libraryID = yield this._getURIObjectLibraryID(uri);
    458 		if (!libraryID) {
    459 			return false;
    460 		}
    461 		
    462 		let retObj = { libraryID };
    463 		if (!uriParts[5]) {
    464 			// References the library itself
    465 			return false;
    466 		}
    467 		
    468 		retObj.objectType = uriParts[5] == 'items' ? 'item' : 'collection';
    469 		retObj.key = uriParts[6];
    470 		
    471 		if (type && type != retObj.objectType) return false;
    472 		
    473 		return retObj;
    474 	});
    475 }