You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/02/12 00:20:58 UTC
[14/41] lots of updates
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/9dfc5628/sdks/html5-javascript/usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.js b/sdks/html5-javascript/usergrid.js
index c8cdfbf..8990b83 100644
--- a/sdks/html5-javascript/usergrid.js
+++ b/sdks/html5-javascript/usergrid.js
@@ -1,949 +1,863 @@
-/*! usergrid@0.0.0 2014-02-01 */
-/*
- * This module is a collection of classes designed to make working with
- * the Appigee App Services API as easy as possible.
- * Learn more at http://apigee.com/docs/usergrid
- *
- * Copyright 2012 Apigee Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @author rod simpson (rod@apigee.com)
- * @author matt dobson (matt@apigee.com)
- * @author ryan bridges (rbridges@apigee.com)
- */
-//Hack around IE console.log
-window.console = window.console || {};
-
-window.console.log = window.console.log || function() {};
-
-//Usergrid namespace encapsulates this SDK
-window.Usergrid = window.Usergrid || {};
-
-Usergrid = Usergrid || {};
-
-Usergrid.USERGRID_SDK_VERSION = "0.10.07";
-
-/*
- * Tests if the string is a uuid
- *
- * @public
- * @method isUUID
- * @param {string} uuid The string to test
- * @returns {Boolean} true if string is uuid
- */
-var uuidValueRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
-
-function isUUID(uuid) {
- if (!uuid) {
- return false;
- }
- return uuidValueRegex.test(uuid);
-}
-
-/*
- * method to encode the query string parameters
- *
- * @method encodeParams
- * @public
- * @params {object} params - an object of name value pairs that will be urlencoded
- * @return {string} Returns the encoded string
- */
-function encodeParams(params) {
- var tail = [];
- var item = [];
- var i;
- if (params instanceof Array) {
- for (i in params) {
- item = params[i];
- if (item instanceof Array && item.length > 1) {
- tail.push(item[0] + "=" + encodeURIComponent(item[1]));
- }
- }
- } else {
- for (var key in params) {
- if (params.hasOwnProperty(key)) {
- var value = params[key];
- if (value instanceof Array) {
- for (i in value) {
- item = value[i];
- tail.push(key + "=" + encodeURIComponent(item));
- }
- } else {
- tail.push(key + "=" + encodeURIComponent(value));
- }
+/*! usergrid@0.0.0 2014-02-06 */
+var UsergridEventable = function() {
+ throw Error("'UsergridEventable' is not intended to be invoked directly");
+};
+
+UsergridEventable.prototype = {
+ bind: function(event, fn) {
+ this._events = this._events || {};
+ this._events[event] = this._events[event] || [];
+ this._events[event].push(fn);
+ },
+ unbind: function(event, fn) {
+ this._events = this._events || {};
+ if (event in this._events === false) return;
+ this._events[event].splice(this._events[event].indexOf(fn), 1);
+ },
+ trigger: function(event) {
+ this._events = this._events || {};
+ if (event in this._events === false) return;
+ for (var i = 0; i < this._events[event].length; i++) {
+ this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
+ }
+ }
+};
+
+UsergridEventable.mixin = function(destObject) {
+ var props = [ "bind", "unbind", "trigger" ];
+ for (var i = 0; i < props.length; i++) {
+ if (props[i] in destObject.prototype) {
+ console.warn("overwriting '" + props[i] + "' on '" + destObject.name + "'.");
+ console.warn("the previous version can be found at '_" + props[i] + "' on '" + destObject.name + "'.");
+ destObject.prototype["_" + props[i]] = destObject.prototype[props[i]];
+ }
+ destObject.prototype[props[i]] = UsergridEventable.prototype[props[i]];
+ }
+};
+
+//Logger
+(function() {
+ var name = "Logger", global = this, overwrittenName = global[name], exports;
+ /* logging */
+ function Logger(name) {
+ this.logEnabled = true;
+ this.init(name, true);
+ }
+ Logger.METHODS = [ "log", "error", "warn", "info", "debug", "assert", "clear", "count", "dir", "dirxml", "exception", "group", "groupCollapsed", "groupEnd", "profile", "profileEnd", "table", "time", "timeEnd", "trace" ];
+ Logger.prototype.init = function(name, logEnabled) {
+ this.name = name || "UNKNOWN";
+ this.logEnabled = logEnabled || true;
+ var addMethod = function(method) {
+ this[method] = this.createLogMethod(method);
+ }.bind(this);
+ Logger.METHODS.forEach(addMethod);
+ };
+ Logger.prototype.createLogMethod = function(method) {
+ return Logger.prototype.log.bind(this, method);
+ };
+ Logger.prototype.prefix = function(method, args) {
+ var prepend = "[" + method.toUpperCase() + "][" + name + "]: ";
+ if ([ "log", "error", "warn", "info" ].indexOf(method) !== -1) {
+ if ("string" === typeof args[0]) {
+ args[0] = prepend + args[0];
+ } else {
+ args.unshift(prepend);
}
}
- }
- return tail.join("&");
-}
-
-/*
- * method to determine whether or not the passed variable is a function
- *
- * @method isFunction
- * @public
- * @params {any} f - any variable
- * @return {boolean} Returns true or false
- */
-function isFunction(f) {
- return f && f !== null && typeof f === "function";
-}
-
-/*
- * a safe wrapper for executing a callback
- *
- * @method doCallback
- * @public
- * @params {Function} callback - the passed-in callback method
- * @params {Array} params - an array of arguments to pass to the callback
- * @params {Object} context - an optional calling context for the callback
- * @return Returns whatever would be returned by the callback. or false.
- */
-function doCallback(callback, params, context) {
- var returnValue;
- if (isFunction(callback)) {
- if (!params) params = [];
- if (!context) context = this;
- params.push(context);
- try {
- returnValue = callback.apply(context, params);
- } catch (ex) {
- if (console && console.error) {
- console.error("Callback error:", ex);
+ return args;
+ };
+ Logger.prototype.log = function() {
+ var args = [].slice.call(arguments);
+ method = args.shift();
+ if (Logger.METHODS.indexOf(method) === -1) {
+ method = "log";
+ }
+ if (!(this.logEnabled && console && console[method])) return;
+ args = this.prefix(method, args);
+ console[method].apply(console, args);
+ };
+ Logger.prototype.setLogEnabled = function(logEnabled) {
+ this.logEnabled = logEnabled || true;
+ };
+ Logger.mixin = function(destObject) {
+ destObject.__logger = new Logger(destObject.name || "UNKNOWN");
+ var addMethod = function(method) {
+ if (method in destObject.prototype) {
+ console.warn("overwriting '" + method + "' on '" + destObject.name + "'.");
+ console.warn("the previous version can be found at '_" + method + "' on '" + destObject.name + "'.");
+ destObject.prototype["_" + method] = destObject.prototype[method];
}
+ destObject.prototype[method] = destObject.__logger.createLogMethod(method);
+ };
+ Logger.METHODS.forEach(addMethod);
+ };
+ global[name] = Logger;
+ global[name].noConflict = function() {
+ if (overwrittenName) {
+ global[name] = overwrittenName;
}
- }
- return returnValue;
-}
-
-Usergrid.Client = function(options) {
- //usergrid enpoint
- this.URI = options.URI || "https://api.usergrid.com";
- //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
- if (options.orgName) {
- this.set("orgName", options.orgName);
- }
- if (options.appName) {
- this.set("appName", options.appName);
- }
- //other options
- this.buildCurl = options.buildCurl || false;
- this.logging = options.logging || false;
- //timeout and callbacks
- this._callTimeout = options.callTimeout || 3e4;
- //default to 30 seconds
- this._callTimeoutCallback = options.callTimeoutCallback || null;
- this.logoutCallback = options.logoutCallback || null;
-};
-
-/*
- * Main function for making requests to the API. Can be called directly.
- *
- * options object:
- * `method` - http method (GET, POST, PUT, or DELETE), defaults to GET
- * `qs` - object containing querystring values to be appended to the uri
- * `body` - object containing entity body for POST and PUT requests
- * `endpoint` - API endpoint, for example 'users/fred'
- * `mQuery` - boolean, set to true if running management query, defaults to false
- *
- * @method request
- * @public
- * @params {object} options
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.request = function(options, callback) {
- var self = this;
- var method = options.method || "GET";
- var endpoint = options.endpoint;
- var body = options.body || {};
- var qs = options.qs || {};
- var mQuery = options.mQuery || false;
- //is this a query to the management endpoint?
- var orgName = this.get("orgName");
- var appName = this.get("appName");
- var uri;
- if (!mQuery && !orgName && !appName) {
- if (typeof this.logoutCallback === "function") {
- return this.logoutCallback(true, "no_org_or_app_name_specified");
- }
- }
- if (mQuery) {
- uri = this.URI + "/" + endpoint;
- } else {
- uri = this.URI + "/" + orgName + "/" + appName + "/" + endpoint;
- }
- if (self.getToken()) {
- qs.access_token = self.getToken();
- }
- //append params to the path
- var encoded_params = encodeParams(qs);
- if (encoded_params) {
- uri += "?" + encoded_params;
- }
- //stringify the body object
- body = JSON.stringify(body);
- //so far so good, so run the query
- var xhr = new XMLHttpRequest();
- xhr.open(method, uri, true);
- //add content type = json if there is a json payload
- if (body) {
- xhr.setRequestHeader("Content-Type", "application/json");
- xhr.setRequestHeader("Accept", "application/json");
- }
- // Handle response.
- xhr.onerror = function(response) {
- self._end = new Date().getTime();
- if (self.logging) {
- console.log("success (time: " + self.calcTimeDiff() + "): " + method + " " + uri);
- }
- if (self.logging) {
- console.log("Error: API call failed at the network level.");
- }
- //network error
- clearTimeout(timeout);
- var err = true;
- if (typeof callback === "function") {
- callback(err, response);
- }
+ return Logger;
};
- xhr.onload = function(response) {
- //call timing, get time, then log the call
- self._end = new Date().getTime();
- if (self.logging) {
- console.log("success (time: " + self.calcTimeDiff() + "): " + method + " " + uri);
- }
- //call completed
- clearTimeout(timeout);
- //decode the response
- try {
- response = JSON.parse(xhr.responseText);
- } catch (e) {
- response = {
- error: "unhandled_error",
- error_description: xhr.responseText
- };
- xhr.status = xhr.status === 200 ? 400 : xhr.status;
- console.error(e);
- }
- if (xhr.status != 200) {
- //there was an api error
- var error = response.error;
- var error_description = response.error_description;
- if (self.logging) {
- console.log("Error (" + xhr.status + ")(" + error + "): " + error_description);
- }
- if (error == "auth_expired_session_token" || error == "auth_missing_credentials" || error == "auth_unverified_oath" || error == "expired_token" || error == "unauthorized" || error == "auth_invalid") {
- //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
- //if the user has specified a logout callback:
- if (typeof self.logoutCallback === "function") {
- return self.logoutCallback(true, response);
- }
- }
- if (typeof callback === "function") {
- callback(true, response);
- }
+ return global[name];
+})();
+
+//Promise
+(function(global) {
+ var name = "Promise", overwrittenName = global[name], exports;
+ function Promise() {
+ this.complete = false;
+ this.error = null;
+ this.result = null;
+ this.callbacks = [];
+ }
+ Promise.prototype.create = function() {
+ return new Promise();
+ };
+ Promise.prototype.then = function(callback, context) {
+ var f = function() {
+ return callback.apply(context, arguments);
+ };
+ if (this.complete) {
+ f(this.error, this.result);
} else {
- if (typeof callback === "function") {
- callback(false, response);
- }
+ this.callbacks.push(f);
}
};
- var timeout = setTimeout(function() {
- xhr.abort();
- if (self._callTimeoutCallback === "function") {
- self._callTimeoutCallback("API CALL TIMEOUT");
- } else {
- self.callback("API CALL TIMEOUT");
+ Promise.prototype.done = function(error, result) {
+ this.complete = true;
+ this.error = error;
+ this.result = result;
+ if (this.callbacks) {
+ for (var i = 0; i < this.callbacks.length; i++) this.callbacks[i](error, result);
+ this.callbacks.length = 0;
}
- }, self._callTimeout);
- //set for 30 seconds
- if (this.logging) {
- console.log("calling: " + method + " " + uri);
- }
- if (this.buildCurl) {
- var curlOptions = {
- uri: uri,
- body: body,
- method: method
- };
- this.buildCurlCall(curlOptions);
- }
- this._start = new Date().getTime();
- xhr.send(body);
-};
-
-/*
- * function for building asset urls
- *
- * @method buildAssetURL
- * @public
- * @params {string} uuid
- * @return {string} assetURL
- */
-Usergrid.Client.prototype.buildAssetURL = function(uuid) {
- var self = this;
- var qs = {};
- var assetURL = this.URI + "/" + this.orgName + "/" + this.appName + "/assets/" + uuid + "/data";
- if (self.getToken()) {
- qs.access_token = self.getToken();
- }
- //append params to the path
- var encoded_params = encodeParams(qs);
- if (encoded_params) {
- assetURL += "?" + encoded_params;
- }
- return assetURL;
-};
-
-/*
- * Main function for creating new groups. Call this directly.
- *
- * @method createGroup
- * @public
- * @params {string} path
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.createGroup = function(options, callback) {
- var getOnExist = options.getOnExist || false;
- options = {
- path: options.path,
- client: this,
- data: options
};
- var group = new Usergrid.Group(options);
- group.fetch(function(err, data) {
- var okToSave = err && "service_resource_not_found" === data.error || "no_name_specified" === data.error || "null_pointer" === data.error || !err && getOnExist;
- if (okToSave) {
- group.save(function(err, data) {
- if (typeof callback === "function") {
- callback(err, group);
+ Promise.join = function(promises) {
+ var p = new Promise(), total = promises.length, completed = 0, errors = [], results = [];
+ function notifier(i) {
+ return function(error, result) {
+ completed += 1;
+ errors[i] = error;
+ results[i] = result;
+ if (completed === total) {
+ p.done(errors, results);
}
- });
- } else {
- if (typeof callback === "function") {
- callback(err, group);
- }
+ };
}
- });
-};
-
-/*
- * Main function for creating new entities - should be called directly.
- *
- * options object: options {data:{'type':'collection_type', 'key':'value'}, uuid:uuid}}
- *
- * @method createEntity
- * @public
- * @params {object} options
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.createEntity = function(options, callback) {
- // todo: replace the check for new / save on not found code with simple save
- // when users PUT on no user fix is in place.
- var getOnExist = options.getOnExist || false;
- //if true, will return entity if one already exists
- delete options.getOnExist;
- //so it doesn't become part of our data model
- var options = {
- client: this,
- data: options
+ for (var i = 0; i < total; i++) {
+ promises[i]().then(notifier(i));
+ }
+ return p;
};
- var entity = new Usergrid.Entity(options);
- entity.fetch(function(err, data) {
- //if the fetch doesn't find what we are looking for, or there is no error, do a save
- var okToSave = err && "service_resource_not_found" === data.error || "no_name_specified" === data.error || "null_pointer" === data.error || !err && getOnExist;
- if (okToSave) {
- entity.set(options.data);
- //add the data again just in case
- entity.save(function(err, data) {
- if (typeof callback === "function") {
- callback(err, entity, data);
+ Promise.chain = function(promises, error, result) {
+ var p = new Promise();
+ if (promises === null || promises.length === 0) {
+ p.done(error, result);
+ } else {
+ promises[0](error, result).then(function(res, err) {
+ promises.splice(0, 1);
+ //self.logger.info(promises.length)
+ if (promises) {
+ Promise.chain(promises, res, err).then(function(r, e) {
+ p.done(r, e);
+ });
+ } else {
+ p.done(res, err);
}
});
- } else {
- if (typeof callback === "function") {
- callback(err, entity, data);
- }
}
- });
-};
-
-/*
- * Main function for getting existing entities - should be called directly.
- *
- * You must supply a uuid or (username or name). Username only applies to users.
- * Name applies to all custom entities
- *
- * options object: options {data:{'type':'collection_type', 'name':'value', 'username':'value'}, uuid:uuid}}
- *
- * @method createEntity
- * @public
- * @params {object} options
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.getEntity = function(options, callback) {
- var options = {
- client: this,
- data: options
+ return p;
};
- var entity = new Usergrid.Entity(options);
- entity.fetch(function(err, data) {
- if (typeof callback === "function") {
- callback(err, entity, data);
+ global[name] = Promise;
+ global[name].noConflict = function() {
+ if (overwrittenName) {
+ global[name] = overwrittenName;
}
- });
-};
-
-/*
- * Main function for restoring an entity from serialized data.
- *
- * serializedObject should have come from entityObject.serialize();
- *
- * @method restoreEntity
- * @public
- * @param {string} serializedObject
- * @return {object} Entity Object
- */
-Usergrid.Client.prototype.restoreEntity = function(serializedObject) {
- var data = JSON.parse(serializedObject);
- var options = {
- client: this,
- data: data
+ return Promise;
};
- var entity = new Usergrid.Entity(options);
- return entity;
-};
-
-/*
- * Main function for creating new collections - should be called directly.
- *
- * options object: options {client:client, type: type, qs:qs}
- *
- * @method createCollection
- * @public
- * @params {object} options
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.createCollection = function(options, callback) {
- options.client = this;
- var collection = new Usergrid.Collection(options, function(err, data) {
- if (typeof callback === "function") {
- callback(err, collection, data);
- }
- });
-};
-
-/*
- * Main function for restoring a collection from serialized data.
- *
- * serializedObject should have come from collectionObject.serialize();
- *
- * @method restoreCollection
- * @public
- * @param {string} serializedObject
- * @return {object} Collection Object
- */
-Usergrid.Client.prototype.restoreCollection = function(serializedObject) {
- var data = JSON.parse(serializedObject);
- data.client = this;
- var collection = new Usergrid.Collection(data);
- return collection;
-};
-
-/*
- * Main function for retrieving a user's activity feed.
- *
- * @method getFeedForUser
- * @public
- * @params {string} username
- * @param {function} callback
- * @return {callback} callback(err, data, activities)
- */
-Usergrid.Client.prototype.getFeedForUser = function(username, callback) {
- var options = {
- method: "GET",
- endpoint: "users/" + username + "/feed"
+ return global[name];
+})(this);
+
+//Ajax
+(function() {
+ var name = "Ajax", global = this, overwrittenName = global[name], exports;
+ Function.prototype.partial = function() {
+ var fn = this, b = [].slice.call(arguments);
+ return fn.bind(undefined, b);
};
- this.request(options, function(err, data) {
- if (typeof callback === "function") {
- if (err) {
- callback(err);
- } else {
- callback(err, data, data.entities);
+ exports = function() {
+ function Ajax() {
+ this.logger = new global.Logger(name);
+ var self = this;
+ function encode(data) {
+ var result = "";
+ if (typeof data === "string") {
+ result = data;
+ } else {
+ var e = encodeURIComponent;
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ result += "&" + e(i) + "=" + e(data[i]);
+ }
+ }
+ }
+ return result;
}
- }
- });
-};
-
-/*
- * Function for creating new activities for the current user - should be called directly.
- *
- * //user can be any of the following: "me", a uuid, a username
- * Note: the "me" alias will reference the currently logged in user (e.g. 'users/me/activties')
- *
- * //build a json object that looks like this:
- * var options =
- * {
- * "actor" : {
- * "displayName" :"myusername",
- * "uuid" : "myuserid",
- * "username" : "myusername",
- * "email" : "myemail",
- * "picture": "http://path/to/picture",
- * "image" : {
- * "duration" : 0,
- * "height" : 80,
- * "url" : "http://www.gravatar.com/avatar/",
- * "width" : 80
- * },
- * },
- * "verb" : "post",
- * "content" : "My cool message",
- * "lat" : 48.856614,
- * "lon" : 2.352222
- * }
- *
- * @method createEntity
- * @public
- * @params {string} user // "me", a uuid, or a username
- * @params {object} options
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.createUserActivity = function(user, options, callback) {
- options.type = "users/" + user + "/activities";
- var options = {
- client: this,
- data: options
+ var request = function(m, u, d) {
+ var p = new Promise(), timeout;
+ self.logger.time(m + " " + u);
+ self.logger.timeEnd(m + " " + u);
+ (function(xhr) {
+ xhr.onreadystatechange = function() {
+ this.readyState ^ 4 || (self.logger.timeEnd(m + " " + u), clearTimeout(timeout),
+ p.done(null, this));
+ };
+ xhr.onerror = function(response) {
+ clearTimeout(timeout);
+ p.done(response, null);
+ };
+ xhr.oncomplete = function(response) {
+ clearTimeout(timeout);
+ self.info("%s request to %s returned %s", m, u, this.status);
+ };
+ xhr.open(m, u);
+ if (d) {
+ xhr.setRequestHeader("Content-Type", "application/json");
+ xhr.setRequestHeader("Accept", "application/json");
+ }
+ timeout = setTimeout(function() {
+ xhr.abort();
+ p.done("API Call timed out.", null);
+ }, 3e4);
+ //TODO stick that timeout in a config variable
+ xhr.send(encode(d));
+ })(new XMLHttpRequest());
+ return p;
+ };
+ this.request = request;
+ this.get = request.partial("GET");
+ this.post = request.partial("POST");
+ this.put = request.partial("PUT");
+ this.delete = request.partial("DELETE");
+ }
+ return new Ajax();
+ }();
+ global[name] = exports;
+ global[name].noConflict = function() {
+ if (overwrittenName) {
+ global[name] = overwrittenName;
+ }
+ return exports;
};
- var entity = new Usergrid.Entity(options);
- entity.save(function(err, data) {
- if (typeof callback === "function") {
- callback(err, entity);
- }
- });
-};
+ return global[name];
+})();
-/*
- * Function for creating user activities with an associated user entity.
- *
- * user object:
- * The user object passed into this function is an instance of Usergrid.Entity.
- *
- * @method createUserActivityWithEntity
- * @public
- * @params {object} user
- * @params {string} content
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.createUserActivityWithEntity = function(user, content, callback) {
- var username = user.get("username");
- var options = {
- actor: {
- displayName: username,
- uuid: user.get("uuid"),
- username: username,
- email: user.get("email"),
- picture: user.get("picture"),
- image: {
- duration: 0,
- height: 80,
- url: user.get("picture"),
- width: 80
- }
- },
- verb: "post",
- content: content
- };
- this.createUserActivity(username, options, callback);
-};
+function UsergridStorable(storage, keyPrefix) {}
-/*
- * A private method to get call timing of last call
- */
-Usergrid.Client.prototype.calcTimeDiff = function() {
- var seconds = 0;
- var time = this._end - this._start;
- try {
- seconds = (time / 10 / 60).toFixed(2);
- } catch (e) {
- return 0;
+UsergridStorable.prototype.setStorage = function(storage) {
+ if (!(storage instanceof Storage)) {
+ console.warn("parameter passed to 'setStorage' is not a browser Storage interface. using sessionStorage");
+ storage = sessionStorage;
}
- return seconds;
-};
-
-/*
- * A public method to store the OAuth token for later use - uses localstorage if available
- *
- * @method setToken
- * @public
- * @params {string} token
- * @return none
- */
-Usergrid.Client.prototype.setToken = function(token) {
- this.set("token", token);
-};
-
-/*
- * A public method to get the OAuth token
- *
- * @method getToken
- * @public
- * @return {string} token
- */
-Usergrid.Client.prototype.getToken = function() {
- return this.get("token");
+ return this._storage = storage;
};
-Usergrid.Client.prototype.setObject = function(key, value) {
- if (value) {
- value = JSON.stringify(value);
+UsergridStorable.prototype.getStorage = function() {
+ if (!(this._storage instanceof Storage)) {
+ console.warn("parameter passed to 'setStorage' is not a browser Storage interface. using sessionStorage");
+ this._storage = sessionStorage;
}
- this.set(key, value);
+ return this._storage;
};
-Usergrid.Client.prototype.set = function(key, value) {
- var keyStore = "apigee_" + key;
- this[key] = value;
- if (typeof Storage !== "undefined") {
- if (value) {
- localStorage.setItem(keyStore, value);
- } else {
- localStorage.removeItem(keyStore);
- }
- }
-};
-
-Usergrid.Client.prototype.getObject = function(key) {
- return JSON.parse(this.get(key));
-};
-
-Usergrid.Client.prototype.get = function(key) {
- var keyStore = "apigee_" + key;
- if (this[key]) {
- return this[key];
- } else if (typeof Storage !== "undefined") {
- return localStorage.getItem(keyStore);
- }
- return null;
-};
-
-/*
- * A public facing helper method for signing up users
- *
- * @method signup
- * @public
- * @params {string} username
- * @params {string} password
- * @params {string} email
- * @params {string} name
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.signup = function(username, password, email, name, callback) {
- var self = this;
- var options = {
- type: "users",
- username: username,
- password: password,
- email: email,
- name: name
- };
- this.createEntity(options, callback);
-};
-
-/*
- *
- * A public method to log in an app user - stores the token for later use
- *
- * @method login
- * @public
- * @params {string} username
- * @params {string} password
- * @param {function} callback
- * @return {callback} callback(err, data)
- */
-Usergrid.Client.prototype.login = function(username, password, callback) {
- var self = this;
- var options = {
- method: "POST",
- endpoint: "token",
- body: {
- username: username,
- password: password,
- grant_type: "password"
- }
- };
- this.request(options, function(err, data) {
- var user = {};
- if (err && self.logging) {
- console.log("error trying to log user in");
- } else {
- var options = {
- client: self,
- data: data.user
- };
- user = new Usergrid.Entity(options);
- self.setToken(data.access_token);
- }
- if (typeof callback === "function") {
- callback(err, data, user);
- }
- });
+UsergridStorable.prototype.getStorageKey = function(key) {
+ if (!this._keyPrefix) this._keyPrefix = "usergrid_js_sdk_";
+ return this._keyPrefix + key;
};
-Usergrid.Client.prototype.reAuthenticateLite = function(callback) {
- var self = this;
- var options = {
- method: "GET",
- endpoint: "management/me",
- mQuery: true
- };
- this.request(options, function(err, response) {
- if (err && self.logging) {
- console.log("error trying to re-authenticate user");
- } else {
- //save the re-authed token and current email/username
- self.setToken(response.access_token);
- }
- if (typeof callback === "function") {
- callback(err);
+UsergridStorable.prototype.get = function(key) {
+ var value;
+ if (arguments.length > 1) {
+ key = [].slice.call(arguments).reduce(function(p, c, i, a) {
+ if (c instanceof Array) {
+ p = p.concat(c);
+ } else {
+ p.push(c);
+ }
+ return p;
+ }, []);
+ }
+ if (this._storage instanceof Storage) {
+ if (key instanceof Array) {
+ var self = this;
+ value = key.map(function(k) {
+ return self.get(k);
+ });
+ } else if ("undefined" !== typeof key) {
+ this[key] = JSON.parse(this.getStorage().getItem(this.getStorageKey(key)));
+ value = this[key];
}
- });
+ }
+ return value;
};
-Usergrid.Client.prototype.reAuthenticate = function(email, callback) {
- var self = this;
- var options = {
- method: "GET",
- endpoint: "management/users/" + email,
- mQuery: true
- };
- this.request(options, function(err, response) {
- var organizations = {};
- var applications = {};
- var user = {};
- var data;
- if (err && self.logging) {
- console.log("error trying to full authenticate user");
- } else {
- data = response.data;
- self.setToken(data.token);
- self.set("email", data.email);
- //delete next block and corresponding function when iframes are refactored
- localStorage.setItem("accessToken", data.token);
- localStorage.setItem("userUUID", data.uuid);
- localStorage.setItem("userEmail", data.email);
- //end delete block
- var userData = {
- username: data.username,
- email: data.email,
- name: data.name,
- uuid: data.uuid
- };
- var options = {
- client: self,
- data: userData
- };
- user = new Usergrid.Entity(options);
- organizations = data.organizations;
- var org = "";
- try {
- //if we have an org stored, then use that one. Otherwise, use the first one.
- var existingOrg = self.get("orgName");
- org = organizations[existingOrg] ? organizations[existingOrg] : organizations[Object.keys(organizations)[0]];
- self.set("orgName", org.name);
- } catch (e) {
- err = true;
- if (self.logging) {
- console.log("error selecting org");
- }
- }
- //should always be an org
- applications = self.parseApplicationsArray(org);
- self.selectFirstApp(applications);
- self.setObject("organizations", organizations);
- self.setObject("applications", applications);
- }
- if (typeof callback === "function") {
- callback(err, data, user, organizations, applications);
+UsergridStorable.prototype.set = function(key, value) {
+ if (this._storage instanceof Storage) {
+ if (value) {
+ this[key] = JSON.stringify(value);
+ this.getStorage().setItem(this.getStorageKey(key), this[key]);
+ } else {
+ delete this[key];
+ this.getStorage().removeItem(this.getStorageKey(key));
}
- });
+ }
};
/*
- * A public method to log in an app user with facebook - stores the token for later use
+ * A public method to store the OAuth token for later use - uses localstorage if available
*
- * @method loginFacebook
+ * @method setToken
* @public
- * @params {string} username
- * @params {string} password
- * @param {function} callback
- * @return {callback} callback(err, data)
+ * @params {string} token
+ * @return none
*/
-Usergrid.Client.prototype.loginFacebook = function(facebookToken, callback) {
- var self = this;
- var options = {
- method: "GET",
- endpoint: "auth/facebook",
- qs: {
- fb_access_token: facebookToken
- }
- };
- this.request(options, function(err, data) {
- var user = {};
- if (err && self.logging) {
- console.log("error trying to log user in");
- } else {
- var options = {
- client: self,
- data: data.user
- };
- user = new Usergrid.Entity(options);
- self.setToken(data.access_token);
- }
- if (typeof callback === "function") {
- callback(err, data, user);
- }
- });
+UsergridStorable.prototype.setToken = function(token) {
+ return this.set("token", token);
};
/*
- * A public method to get the currently logged in user entity
+ * A public method to get the OAuth token
*
- * @method getLoggedInUser
+ * @method getToken
* @public
- * @param {function} callback
- * @return {callback} callback(err, data)
+ * @return {string} token
*/
-Usergrid.Client.prototype.getLoggedInUser = function(callback) {
- if (!this.getToken()) {
- callback(true, null, null);
- } else {
- var self = this;
- var options = {
- method: "GET",
- endpoint: "users/me"
- };
- this.request(options, function(err, data) {
- if (err) {
- if (self.logging) {
- console.log("error trying to log user in");
- }
- if (typeof callback === "function") {
- callback(err, data, null);
- }
- } else {
- var options = {
- client: self,
- data: data.entities[0]
- };
- var user = new Usergrid.Entity(options);
- if (typeof callback === "function") {
- callback(err, data, user);
- }
- }
- });
+UsergridStorable.prototype.getToken = function() {
+ return this.get("token");
+};
+
+UsergridStorable.mixin = function(destObject) {
+ var props = [ "getStorage", "setStorage", "getStorageKey", "get", "set", "getToken", "setToken" ];
+ for (var i = 0; i < props.length; i++) {
+ if (props[i] in destObject.prototype) {
+ console.warn("overwriting '" + props[i] + "' on '" + destObject.name + "'.");
+ console.warn("the previous version can be found at '_" + props[i] + "' on '" + destObject.name + "'.");
+ destObject.prototype["_" + props[i]] = destObject.prototype[props[i]];
+ }
+ destObject.prototype[props[i]] = UsergridStorable.prototype[props[i]];
}
};
/*
- * A public method to test if a user is logged in - does not guarantee that the token is still valid,
- * but rather that one exists
+ * This module is a collection of classes designed to make working with
+ * the Appigee App Services API as easy as possible.
+ * Learn more at http://Usergrid.com/docs/usergrid
*
- * @method isLoggedIn
- * @public
- * @return {boolean} Returns true the user is logged in (has token and uuid), false if not
+ * Copyright 2012 Usergrid Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @author rod simpson (rod@Usergrid.com)
+ * @author matt dobson (matt@Usergrid.com)
+ * @author ryan bridges (rbridges@Usergrid.com)
*/
-Usergrid.Client.prototype.isLoggedIn = function() {
- if (this.getToken() && this.getToken() != "null") {
- return true;
+//Hack around IE console.log
+window.console = window.console || {};
+
+window.console.log = window.console.log || function() {};
+
+function extend(subClass, superClass) {
+ var F = function() {};
+ F.prototype = superClass.prototype;
+ subClass.prototype = new F();
+ subClass.prototype.constructor = subClass;
+ subClass.superclass = superClass.prototype;
+ if (superClass.prototype.constructor == Object.prototype.constructor) {
+ superClass.prototype.constructor = superClass;
}
- return false;
-};
+ return subClass;
+}
+
+function NOOP() {}
+
+//Usergrid namespace encapsulates this SDK
+/*window.Usergrid = window.Usergrid || {};
+Usergrid = Usergrid || {};
+Usergrid.USERGRID_SDK_VERSION = '0.10.07';*/
+function isValidUrl(url) {
+ if (!url) return false;
+ var doc, base, anchor, isValid = false;
+ try {
+ doc = document.implementation.createHTMLDocument("");
+ base = doc.createElement("base");
+ base.href = base || window.lo;
+ doc.head.appendChild(base);
+ anchor = doc.createElement("a");
+ anchor.href = url;
+ doc.body.appendChild(anchor);
+ isValid = !(anchor.href === "");
+ } catch (e) {
+ console.error(e);
+ } finally {
+ doc.head.removeChild(base);
+ doc.body.removeChild(anchor);
+ base = null;
+ anchor = null;
+ doc = null;
+ return isValid;
+ }
+}
+
+/*
+ * Tests if the string is a uuid
+ *
+ * @public
+ * @method isUUID
+ * @param {string} uuid The string to test
+ * @returns {Boolean} true if string is uuid
+ */
+var uuidValueRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
+
+function isUUID(uuid) {
+ return !uuid ? false : uuidValueRegex.test(uuid);
+}
/*
- * A public method to log out an app user - clears all user fields from client
+ * method to encode the query string parameters
*
- * @method logout
+ * @method encodeParams
* @public
- * @return none
+ * @params {object} params - an object of name value pairs that will be urlencoded
+ * @return {string} Returns the encoded string
*/
-Usergrid.Client.prototype.logout = function() {
- this.setToken(null);
-};
+function encodeParams(params) {
+ var queryString;
+ if (params && Object.keys(params)) {
+ queryString = [].slice.call(arguments).reduce(function(a, b) {
+ return a.concat(b instanceof Array ? b : [ b ]);
+ }, []).filter(function(c) {
+ return "object" === typeof c;
+ }).reduce(function(p, c) {
+ !(c instanceof Array) ? p = p.concat(Object.keys(c).map(function(key) {
+ return [ key, c[key] ];
+ })) : p.push(c);
+ return p;
+ }, []).reduce(function(p, c) {
+ c.length === 2 ? p.push(c) : p = p.concat(c);
+ return p;
+ }, []).reduce(function(p, c) {
+ c[1] instanceof Array ? c[1].forEach(function(v) {
+ p.push([ c[0], v ]);
+ }) : p.push(c);
+ return p;
+ }, []).map(function(c) {
+ c[1] = encodeURIComponent(c[1]);
+ return c.join("=");
+ }).join("&");
+ }
+ return queryString;
+}
/*
- * A private method to build the curl call to display on the command line
+ * method to determine whether or not the passed variable is a function
*
- * @method buildCurlCall
- * @private
- * @param {object} options
- * @return {string} curl
+ * @method isFunction
+ * @public
+ * @params {any} f - any variable
+ * @return {boolean} Returns true or false
*/
-Usergrid.Client.prototype.buildCurlCall = function(options) {
- var curl = "curl";
- var method = (options.method || "GET").toUpperCase();
- var body = options.body || {};
- var uri = options.uri;
- //curl - add the method to the command (no need to add anything for GET)
- if (method === "POST") {
- curl += " -X POST";
- } else if (method === "PUT") {
- curl += " -X PUT";
- } else if (method === "DELETE") {
- curl += " -X DELETE";
- } else {
- curl += " -X GET";
- }
- //curl - append the path
- curl += " " + uri;
- //curl - add the body
- if ("undefined" !== typeof window) {
- body = JSON.stringify(body);
+function isFunction(f) {
+ return f && f !== null && typeof f === "function";
+}
+
+/*
+ * a safe wrapper for executing a callback
+ *
+ * @method doCallback
+ * @public
+ * @params {Function} callback - the passed-in callback method
+ * @params {Array} params - an array of arguments to pass to the callback
+ * @params {Object} context - an optional calling context for the callback
+ * @return Returns whatever would be returned by the callback. or false.
+ */
+function doCallback(callback, params, context) {
+ var returnValue;
+ if (isFunction(callback)) {
+ if (!params) params = [];
+ if (!context) context = this;
+ params.push(context);
+ try {
+ returnValue = callback.apply(context, params);
+ } catch (ex) {
+ if (console && console.error) {
+ console.error("Callback error:", ex);
+ }
+ }
}
- //only in node module
- if (body !== '"{}"' && method !== "GET" && method !== "DELETE") {
- //curl - add in the json obj
- curl += " -d '" + body + "'";
+ return returnValue;
+}
+
+//noinspection ThisExpressionReferencesGlobalObjectJS
+(function(global) {
+ var name = "Usergrid", overwrittenName = global[name];
+ function Usergrid() {
+ this.logger = new Logger(name);
}
- //log the curl command to the console
- console.log(curl);
- return curl;
-};
+ Usergrid.isValidEndpoint = function(endpoint) {
+ //TODO actually implement this
+ return true;
+ };
+ var VALID_REQUEST_METHODS = [ "GET", "POST", "PUT", "DELETE" ];
+ Usergrid.Request = function(method, endpoint, query_params, data, callback) {
+ var p = new Promise();
+ /*
+ Create a logger
+ */
+ this.logger = new global.Logger("Usergrid.Request");
+ this.logger.time("process request " + method + " " + endpoint);
+ /*
+ Validate our input
+ */
+ this.endpoint = endpoint;
+ this.method = method.toUpperCase();
+ this.query_params = query_params;
+ this.data = "object" === typeof data ? JSON.stringify(data) : data;
+ if (VALID_REQUEST_METHODS.indexOf(this.method) === -1) {
+ throw new UsergridInvalidHTTPMethodError("invalid request method '" + this.method + "'");
+ }
+ /*
+ Prepare our request
+ */
+ if (!isValidUrl(this.endpoint)) {
+ this.logger.error(endpoint, this.endpoint, /^https:\/\//.test(endpoint), api_uri, orgName, appName);
+ throw new UsergridError("The provided endpoint is not valid: " + this.endpoint);
+ }
+ /* a callback to make the request */
+ var request = function() {
+ return Ajax.request(this.method, this.endpoint, this.data);
+ }.bind(this);
+ /* a callback to process the response */
+ var response = function(err, request) {
+ return new Usergrid.Response(err, request);
+ }.bind(this);
+ /* a callback to clean up and return data to the client */
+ var oncomplete = function(err, response) {
+ p.done(err, response);
+ this.logger.info("REQUEST", err, response);
+ doCallback(callback, [ err, response ]);
+ this.logger.timeEnd("process request " + method + " " + endpoint);
+ }.bind(this);
+ /* and a promise to chain them all together */
+ Promise.chain([ request, response ]).then(oncomplete);
+ return p;
+ };
+ Usergrid.Request.prototype = new UsergridStorable();
+ Usergrid.Request.prototype.validate = function() {
+ var p = new Promise();
+ p.done(null, this);
+ return p;
+ };
+ Usergrid.Request.prototype.prepare = function() {
+ var p = new Promise();
+ p.done(null, this);
+ return p;
+ };
+ Usergrid.Request.prototype.fire = function() {
+ var p = new Promise();
+ p.done(null, this);
+ return p;
+ };
+ //TODO more granular handling of statusCodes
+ Usergrid.Response = function(err, response) {
+ var p = new Promise();
+ this.logger = new global.Logger(name);
+ this.success = true;
+ this.err = err;
+ this.data = {};
+ var data;
+ try {
+ data = JSON.parse(response.responseText);
+ } catch (e) {
+ //this.logger.error("Error parsing response text: ",this.text);
+ this.logger.error("Caught error ", e.message);
+ data = {};
+ } finally {
+ this.data = data;
+ }
+ this.status = parseInt(response.status);
+ this.statusGroup = this.status - this.status % 100;
+ switch (this.statusGroup) {
+ case 200:
+ this.success = true;
+ break;
-Usergrid.Client.prototype.getDisplayImage = function(email, picture, size) {
- try {
- if (picture) {
- return picture;
+ case 400:
+ case 500:
+ case 300:
+ case 100:
+ default:
+ //server error
+ this.success = false;
+ break;
}
- var size = size || 50;
- if (email.length) {
- return "https://secure.gravatar.com/avatar/" + MD5(email) + "?s=" + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+ var self = this;
+ if (this.success) {
+ p.done(null, this);
} else {
- return "https://apigee.com/usergrid/images/user_profile.png";
+ p.done(UsergridError.fromResponse(this.data), this);
}
- } catch (e) {
- return "https://apigee.com/usergrid/images/user_profile.png";
- }
-};
+ return p;
+ };
+ Usergrid.Response.prototype.getEntities = function() {
+ var entities = [];
+ if (this.success && this.data.entities) {
+ entities = this.data.entities;
+ }
+ return entities;
+ };
+ Usergrid.Response.prototype.getEntity = function() {
+ var entities = this.getEntities();
+ return entities[0];
+ };
+ Usergrid.Client = function(options) {
+ this.logger = new global.Logger("Usergrid.Client");
+ var self = this;
+ this.getStorage();
+ this.set("api_uri", options.URI || "https://api.usergrid.com");
+ this.set("orgName", options.orgName);
+ this.set("appName", options.appName);
+ //other options
+ this.set("buildCurl", options.buildCurl || false);
+ this.set("logging", options.logging || false);
+ };
+ /*
+ Add browser storage capability (defaults to sessionStorage,
+ but you can inject anything that implements window.Storage
+ eg. client._storage=localStorage;
+ */
+ UsergridStorable.mixin(Usergrid.Client);
+ /*
+ Add rudimentary eventing
+ */
+ UsergridEventable.mixin(Usergrid.Client);
+ /*
+ * function for building asset urls
+ *
+ * @method buildAssetURL
+ * @public
+ * @params {string} uuid
+ * @return {string} assetURL
+ */
+ Usergrid.Client.prototype.buildAssetURL = function(uuid) {
+ var qs = {};
+ var uri_elements = this.get("api_uri", "orgName", "appName");
+ uri_elements = uri_elements.concat([ "assets", uuid, "data" ]);
+ var assetURL = uri_elements.join("/");
+ var token = this.getToken();
+ if (token) {
+ qs.access_token = token;
+ }
+ //append params to the path
+ var encoded_params = encodeParams(qs);
+ if (encoded_params) {
+ assetURL += "?" + encoded_params;
+ }
+ return assetURL;
+ };
+ /*
+ * function for building asset urls
+ *
+ * @method buildAssetURL
+ * @public
+ * @params {string} uuid
+ * @return {string} assetURL
+ */
+ Usergrid.Client.prototype.buildEndpointURL = function(endpoint, qs) {
+ qs = qs || {};
+ var endSlashes = /(^\/|\/$)/g;
+ var assetURL = [ endpoint.replace(endSlashes, "") ].concat(this.get("api_uri", "orgName", "appName"));
+ var token = this.getToken();
+ if (token) {
+ qs.access_token = token;
+ }
+ var encoded_params = encodeParams(qs);
+ if (encoded_params) {
+ assetURL += "?" + encoded_params;
+ }
+ return assetURL;
+ };
+ /*
+ * Main function for making requests to the API. Can be called directly.
+ *
+ * options object:
+ * `method` - http method (GET, POST, PUT, or DELETE), defaults to GET
+ * `qs` - object containing querystring values to be appended to the uri
+ * `body` - object containing entity body for POST and PUT requests
+ * `endpoint` - API endpoint, for example 'users/fred'
+ * `mQuery` - boolean, set to true if running management query, defaults to false
+ *
+ * @method request
+ * @public
+ * @params {object} options
+ * @param {function} callback
+ * @return {callback} callback(err, data)
+ */
+ Usergrid.Client.prototype.request = function(options, callback) {
+ var p = new Promise();
+ var _callback = function(err, data) {
+ p.done(err, data);
+ doCallback(callback, [ err, data ]);
+ };
+ this.logger = new Logger("Request");
+ var self = this;
+ var method = options.method || "GET";
+ var endpoint = options.endpoint;
+ var body = options.body || {};
+ var qs = options.qs || {};
+ var mQuery = options.mQuery || false;
+ //is this a query to the management endpoint?
+ /*
+ could also use headers for the token
+ xhr.setRequestHeader("Authorization", "Bearer " + self.getToken());
+ xhr.withCredentials = true;
+ */
+ var api_uri = this.get("api_uri");
+ var orgName = this.get("orgName");
+ var appName = this.get("appName");
+ if (this.getToken()) qs.access_token = this.getToken();
+ //if(isValidUrl(endpoint)){
+ if (api_uri && orgName && appName) {
+ endpoint = [ api_uri, orgName, appName, endpoint ].join("/");
+ } else {
+ endpoint = [ api_uri, endpoint ].join("/");
+ }
+ var req = new Usergrid.Request(method, endpoint, qs, body, function(err, response) {
+ if ([ "auth_expired_session_token", "auth_missing_credentials", "auth_unverified_oath", "expired_token", "unauthorized", "auth_invalid" ].indexOf(response.error) !== -1) {}
+ doCallback(callback, [ err, response ]);
+ p.done(err, response);
+ });
+ return p;
+ };
+ /*
+ * Main function for creating new entities - should be called directly.
+ *
+ * options object: options {data:{'type':'collection_type', 'key':'value'}, uuid:uuid}}
+ *
+ * @method createEntity
+ * @public
+ * @params {object} options
+ * @param {function} callback
+ * @return {callback} callback(err, data)
+ */
+ Usergrid.Client.prototype.createEntity = function(options, callback) {
+ // todo: replace the check for new / save on not found code with simple save
+ // when users PUT on no user fix is in place.
+ var getOnExist = options["getOnExist"] || false;
+ //if true, will return entity if one already exists
+ delete options["getOnExist"];
+ //so it doesn't become part of our data model
+ var entity_data = {
+ client: this,
+ data: options
+ };
+ var entity = new Usergrid.Entity(entity_data);
+ var self = this;
+ entity.fetch(function(err, data) {
+ console.log(err, data);
+ //if the fetch doesn't find what we are looking for, or there is no error, do a save
+ var common_errors = [ "service_resource_not_found", "no_name_specified", "null_pointer" ];
+ var okToSave = err.name && common_errors.indexOf(err.name) !== -1 || !err && getOnExist;
+ if (okToSave) {
+ entity.set(entity_data.data);
+ //add the data again just in case
+ entity.save(function(err, data) {
+ doCallback(callback, [ err, entity, data ]);
+ });
+ } else {
+ doCallback(callback, [ err, entity, data ]);
+ }
+ });
+ };
+ /*
+ * Main function for getting existing entities - should be called directly.
+ *
+ * You must supply a uuid or (username or name). Username only applies to users.
+ * Name applies to all custom entities
+ *
+ * options object: options {data:{'type':'collection_type', 'name':'value', 'username':'value'}, uuid:uuid}}
+ *
+ * @method createEntity
+ * @public
+ * @params {object} options
+ * @param {function} callback
+ * @return {callback} doCallback(callback, [err, data])
+ */
+ Usergrid.Client.prototype.getEntity = function(options, callback) {
+ var entity_data = {
+ client: this,
+ data: options
+ };
+ var entity = new Usergrid.Entity(entity_data);
+ entity.fetch(function(err, data) {
+ doCallback(callback, [ err, entity, data ]);
+ });
+ };
+ /*
+ * Main function for restoring an entity from serialized data.
+ *
+ * serializedObject should have come from entityObject.serialize();
+ *
+ * @method restoreEntity
+ * @public
+ * @param {string} serializedObject
+ * @return {object} Entity Object
+ */
+ Usergrid.Client.prototype.restoreEntity = function(serializedObject) {
+ return new Usergrid.Entity({
+ client: this,
+ data: JSON.parse(serializedObject)
+ });
+ };
+ /*
+ * Main function for creating new collections - should be called directly.
+ *
+ * options object: options {client:client, type: type, qs:qs}
+ *
+ * @method createCollection
+ * @public
+ * @params {object} options
+ * @param {function} callback
+ * @return {callback} callback(err, data)
+ */
+ Usergrid.Client.prototype.createCollection = function(options, callback) {
+ options.client = this;
+ var collection = new Usergrid.Collection(options, function(err, data) {
+ if (typeof callback === "function") {
+ callback(err, collection, data);
+ }
+ });
+ };
+ //Usergrid.Entity=function(){};
+ //Usergrid.Collection=function(){};
+ global[name] = Usergrid;
+ global[name].noConflict = function() {
+ if (overwrittenName) {
+ global[name] = overwrittenName;
+ }
+ return Usergrid;
+ };
+ return global[name];
+})(this);
/*
* A class to Model a Usergrid Entity.
@@ -967,7 +881,7 @@ Usergrid.Entity = function(options) {
* @params {any} obj - any variable
* @return {boolean} Returns true or false
*/
-Usergrid.isEntity = function(obj) {
+Usergrid.Entity.isEntity = function(obj) {
return obj && obj instanceof Usergrid.Entity;
};
@@ -980,7 +894,7 @@ Usergrid.isEntity = function(obj) {
* @params {any} obj - any variable
* @return {boolean} Returns true or false
*/
-Usergrid.isPersistedEntity = function(obj) {
+Usergrid.Entity.isPersistedEntity = function(obj) {
return isEntity(obj) && isUUID(obj.get("uuid"));
};
@@ -1004,12 +918,29 @@ Usergrid.Entity.prototype.serialize = function() {
* @param {string} field
* @return {string} || {object} data
*/
-Usergrid.Entity.prototype.get = function(field) {
- if (field) {
- return this._data[field];
- } else {
- return this._data;
+Usergrid.Entity.prototype.get = function(key) {
+ var value;
+ if (arguments.length === 0) {
+ value = this._data;
+ } else if (arguments.length > 1) {
+ key = [].slice.call(arguments).reduce(function(p, c, i, a) {
+ if (c instanceof Array) {
+ p = p.concat(c);
+ } else {
+ p.push(c);
+ }
+ return p;
+ }, []);
}
+ if (key instanceof Array) {
+ var self = this;
+ value = key.map(function(k) {
+ return self.get(k);
+ });
+ } else if ("undefined" !== typeof key) {
+ value = this._data[key];
+ }
+ return value;
};
/*
@@ -1038,6 +969,25 @@ Usergrid.Entity.prototype.set = function(key, value) {
}
};
+Usergrid.Entity.prototype.getEndpoint = function() {
+ var type = this.get("type"), name, endpoint;
+ var nameProperties = [ "uuid", "name" ];
+ if (type === undefined) {
+ throw new UsergridError("cannot fetch entity, no entity type specified", "no_type_specified");
+ } else if (type === "users") {
+ nameProperties.unshift("username");
+ }
+ var names = this.get(nameProperties).filter(function(x) {
+ return "undefined" !== typeof x;
+ });
+ if (names.length === 0) {
+ throw new UsergridError("Cannot infer an UUID or type from the entity", "no_name_specified");
+ } else {
+ name = names.shift();
+ }
+ return [ type, name ].join("/");
+};
+
/*
* Saves the entity back to the database
*
@@ -1047,84 +997,35 @@ Usergrid.Entity.prototype.set = function(key, value) {
* @return {callback} callback(err, data)
*/
Usergrid.Entity.prototype.save = function(callback) {
- var type = this.get("type");
- var method = "POST";
- if (isUUID(this.get("uuid"))) {
- method = "PUT";
- type += "/" + this.get("uuid");
- }
- //update the entity
- var self = this;
- var data = {};
- var entityData = this.get();
- var password = this.get("password");
- var oldpassword = this.get("oldpassword");
- var newpassword = this.get("newpassword");
- var SYSTEM_PROPERTIES = [ "metadata", "created", "modified", "oldpassword", "newpassword", "type", "activated", "uuid" ];
- //remove system specific properties
- for (var item in entityData) {
- if (SYSTEM_PROPERTIES.indexOf(item) !== -1) {
- continue;
- }
- data[item] = entityData[item];
- }
- var options = {
+ var self = this, type = this.get("type"), method = "POST", entityId = this.get("uuid"), data = {}, entityData = this.get(), /*password = this.get('password'),
+ oldpassword = this.get('oldpassword'),
+ newpassword = this.get('newpassword'),*/
+ SYSTEM_PROPERTIES = [ "metadata", "created", "modified", "oldpassword", "newpassword", "type", "activated", "uuid" ], options = {
method: method,
- endpoint: type,
- body: data
+ endpoint: type
};
+ console.log("SAVE DATA #1", entityId, entityData);
+ //update the entity
+ if (entityId) {
+ options.method = "PUT";
+ options.endpoint += "/" + entityId;
+ }
+ //remove system-specific properties
+ Object.keys(entityData).filter(function(key) {
+ return SYSTEM_PROPERTIES.indexOf(key) === -1;
+ }).forEach(function(key) {
+ data[key] = entityData[key];
+ });
+ console.log("SAVE DATA #2", data);
+ options.body = data;
//save the entity first
- this._client.request(options, function(err, retdata) {
- //clear out pw info if present
- self.set("password", null);
- self.set("oldpassword", null);
- self.set("newpassword", null);
- if (err && self._client.logging) {
- console.log("could not save entity");
- if (typeof callback === "function") {
- return callback(err, retdata, self);
- }
- } else {
- if (retdata.entities) {
- if (retdata.entities.length) {
- var entity = retdata.entities[0];
- self.set(entity);
- var path = retdata.path;
- //for connections, API returns type
- while (path.substring(0, 1) === "/") {
- path = path.substring(1);
- }
- self.set("type", path);
- }
- }
- //if this is a user, update the password if it has been specified;
- var needPasswordChange = (self.get("type") === "user" || self.get("type") === "users") && oldpassword && newpassword;
- if (needPasswordChange) {
- //Note: we have a ticket in to change PUT calls to /users to accept the password change
- // once that is done, we will remove this call and merge it all into one
- var pwdata = {};
- pwdata.oldpassword = oldpassword;
- pwdata.newpassword = newpassword;
- var options = {
- method: "PUT",
- endpoint: type + "/password",
- body: pwdata
- };
- self._client.request(options, function(err, data) {
- if (err && self._client.logging) {
- console.log("could not update user");
- }
- //remove old and new password fields so they don't end up as part of the entity object
- self.set("oldpassword", null);
- self.set("newpassword", null);
- if (typeof callback === "function") {
- callback(err, data, self);
- }
- });
- } else if (typeof callback === "function") {
- callback(err, retdata, self);
- }
+ this._client.request(options, function(err, response) {
+ console.log("SAVE DATA #3", response);
+ var entity = response.getEntity();
+ if (entity) {
+ self.set(entity);
}
+ doCallback(callback, [ err, self ]);
});
};
@@ -1137,50 +1038,29 @@ Usergrid.Entity.prototype.save = function(callback) {
* @return {callback} callback(err, data)
*/
Usergrid.Entity.prototype.fetch = function(callback) {
- var type = this.get("type");
- var self = this;
+ var endpoint, self = this;
//Check for an entity type, then if a uuid is available, use that, otherwise, use the name
- try {
- if (type === undefined) {
- throw "cannot fetch entity, no entity type specified";
- } else if (this.get("uuid")) {
- type += "/" + this.get("uuid");
- } else if (type === "users" && this.get("username")) {
- type += "/" + this.get("username");
- } else if (this.get("name")) {
- type += "/" + encodeURIComponent(this.get("name"));
- } else if (typeof callback === "function") {
- throw "no_name_specified";
- }
- } catch (e) {
- if (self._client.logging) {
- console.log(e);
- }
- return callback(true, {
- error: e
- }, self);
- }
+ //try {
+ endpoint = this.getEndpoint();
+ /*} catch (e) {
+ if (self._client.logging) {
+ console.log(e);
+ }
+ return callback(true, {
+ error: e
+ }, self);
+ }*/
var options = {
method: "GET",
- endpoint: type
+ endpoint: endpoint
};
- this._client.request(options, function(err, data) {
- if (err && self._client.logging) {
- console.log("could not get entity");
- } else {
- if (data.user) {
- self.set(data.user);
- self._json = JSON.stringify(data.user, null, 2);
- } else if (data.entities) {
- if (data.entities.length) {
- var entity = data.entities[0];
- self.set(entity);
- }
- }
- }
- if (typeof callback === "function") {
- callback(err, data, self);
+ this._client.request(options, function(err, response) {
+ var entity = response.getEntity();
+ if (entity) {
+ self.set(entity);
}
+ console.log("AFTER FETCH", self.get(), entity, response);
+ doCallback(callback, [ err, entity, self ]);
});
};
@@ -1196,30 +1076,17 @@ Usergrid.Entity.prototype.fetch = function(callback) {
*/
Usergrid.Entity.prototype.destroy = function(callback) {
var self = this;
- var type = this.get("type");
- if (isUUID(this.get("uuid"))) {
- type += "/" + this.get("uuid");
- } else {
- if (typeof callback === "function") {
- var error = "Error trying to delete object - no uuid specified.";
- if (self._client.logging) {
- console.log(error);
- }
- callback(true, error);
- }
- }
+ var endpoint = this.getEndpoint();
var options = {
method: "DELETE",
- endpoint: type
+ endpoint: endpoint
};
this._client.request(options, function(err, data) {
- if (err && self._client.logging) {
- console.log("entity could not be deleted");
- } else {
+ if (!err) {
self.set(null);
}
if (typeof callback === "function") {
- callback(err, data);
+ doCallback(callback, [ err, data ]);
}
});
};
@@ -1294,7 +1161,7 @@ Usergrid.Entity.prototype.getEntityId = function(entity) {
if (isUUID(entity.get("uuid"))) {
id = entity.get("uuid");
} else {
- if (type === "users") {
+ if (this.get("type") === "users") {
id = entity.get("username");
} else if (entity.get("name")) {
id = entity.get("name");
@@ -2735,19 +2602,118 @@ Usergrid.Asset.prototype.download = function(callback) {
xhr.send();
};
-Usergrid.Error = function(options) {
- this.name = "UsergridError";
- this.timestamp = options.timestamp || Date.now();
- if (options instanceof Error) {
- this.exception = options.name || "";
- this.message = options.message || "An error has occurred";
- } else if ("object" === typeof options) {
- this.exception = options.error || "unknown_error";
- this.message = options.error_description || "An error has occurred";
- } else if ("string" === typeof options) {
- this.exception = "unknown_error";
- this.message = options || "An error has occurred";
- }
-};
-
-Usergrid.Error.prototype = new Error();
\ No newline at end of file
+//noinspection ThisExpressionReferencesGlobalObjectJS
+/**
+ * Created by ryan bridges on 2014-02-05.
+ */
+(function(global) {
+ //noinspection JSUnusedAssignment
+ var name = "UsergridError", short, _name = global[name], _short = short && short !== undefined ? global[short] : undefined;
+ /*
+ * Instantiates a new UsergridError
+ *
+ * @method UsergridError
+ * @public
+ * @params {<string>} message
+ * @params {<string>} id - the error code, id, or name
+ * @params {<int>} timestamp
+ * @params {<int>} duration
+ * @params {<string>} exception - the Java exception from Usergrid
+ * @return Returns - a new UsergridError object
+ *
+ * Example:
+ *
+ * UsergridError(message);
+ */
+ function UsergridError(message, name, timestamp, duration, exception) {
+ this.message = message;
+ this.name = name;
+ this.timestamp = timestamp || Date.now();
+ this.duration = duration || 0;
+ this.exception = exception;
+ }
+ UsergridError.prototype = new Error();
+ UsergridError.prototype.constructor = UsergridError;
+ /*
+ * Creates a UsergridError from the JSON response returned from the backend
+ *
+ * @method fromResponse
+ * @public
+ * @params {object} response - the deserialized HTTP response from the Usergrid API
+ * @return Returns a new UsergridError object.
+ *
+ * Example:
+ * {
+ * "error":"organization_application_not_found",
+ * "timestamp":1391618508079,
+ * "duration":0,
+ * "exception":"org.usergrid.rest.exceptions.OrganizationApplicationNotFoundException",
+ * "error_description":"Could not find application for yourorgname/sandboxxxxx from URI: yourorgname/sandboxxxxx"
+ * }
+ */
+ UsergridError.fromResponse = function(response) {
+ if (response && "undefined" !== typeof response) {
+ return new UsergridError(response.error_description, response.error, response.timestamp, response.duration, response.exception);
+ } else {
+ return new UsergridError();
+ }
+ };
+ UsergridError.createSubClass = function(name) {
+ if (name in global && global[name]) return global[name];
+ global[name] = function() {};
+ global[name].name = name;
+ global[name].prototype = new UsergridError();
+ return global[name];
+ };
+ function UsergridHTTPResponseError(message, name, timestamp, duration, exception) {
+ this.message = message;
+ this.name = name;
+ this.timestamp = timestamp || Date.now();
+ this.duration = duration || 0;
+ this.exception = exception;
+ }
+ UsergridHTTPResponseError.prototype = new UsergridError();
+ function UsergridInvalidHTTPMethodError(message, name, timestamp, duration, exception) {
+ this.message = message;
+ this.name = name;
+ this.timestamp = timestamp || Date.now();
+ this.duration = duration || 0;
+ this.exception = exception;
+ }
+ UsergridInvalidHTTPMethodError.prototype = new UsergridError();
+ function UsergridInvalidURIError(message, name, timestamp, duration, exception) {
+ this.message = message;
+ this.name = name;
+ this.timestamp = timestamp || Date.now();
+ this.duration = duration || 0;
+ this.exception = exception;
+ }
+ UsergridInvalidURIError.prototype = new UsergridError();
+ function UsergridKeystoreDatabaseUpgradeNeededError(message, name, timestamp, duration, exception) {
+ this.message = message;
+ this.name = name;
+ this.timestamp = timestamp || Date.now();
+ this.duration = duration || 0;
+ this.exception = exception;
+ }
+ UsergridKeystoreDatabaseUpgradeNeededError.prototype = new UsergridError();
+ global["UsergridHTTPResponseError"] = UsergridHTTPResponseError;
+ global["UsergridInvalidHTTPMethodError"] = UsergridInvalidHTTPMethodError;
+ global["UsergridInvalidURIError"] = UsergridInvalidURIError;
+ global["UsergridKeystoreDatabaseUpgradeNeededError"] = UsergridKeystoreDatabaseUpgradeNeededError;
+ global[name] = UsergridError;
+ if (short !== undefined) {
+ //noinspection JSUnusedAssignment
+ global[short] = UsergridError;
+ }
+ global[name].noConflict = function() {
+ if (_name) {
+ global[name] = _name;
+ }
+ if (short !== undefined) {
+ global[short] = _short;
+ }
+ return UsergridError;
+ };
+ return global[name];
+})(this);
\ No newline at end of file