http://git-wip-us.apache.org/repos/asf/usergrid/blob/ada7b36b/content/v101-portal-demo/js/libs/usergrid.sdk.js ---------------------------------------------------------------------- diff --git a/content/v101-portal-demo/js/libs/usergrid.sdk.js b/content/v101-portal-demo/js/libs/usergrid.sdk.js new file mode 100644 index 0000000..d527ea0 --- /dev/null +++ b/content/v101-portal-demo/js/libs/usergrid.sdk.js @@ -0,0 +1,2568 @@ +/* + * 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) + */ +(function(window, localStorage) { + + + //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.SDK_VERSION = '0.10.07'; + Usergrid.browser = Usergrid.browser || {}; + + Usergrid.Client = function(options, url) { + //usergrid enpoint + this.URI = url || '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); + } + + if (options.keys) { + this._keys = options.keys; + } + + //other options + this.buildCurl = options.buildCurl || false; + this.logging = options.logging || false; + + //timeout and callbacks + this._callTimeout = options.callTimeout || 30000; //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) { + callback = callback || function() { + console.error('no callback handed to client.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? + var orgName = this.get("orgName"); + var appName = this.get("appName"); + if (!mQuery && !orgName && !appName) { + if (typeof this.logoutCallback === "function") { + return this.logoutCallback(true, "no_org_or_app_name_specified"); + } + } + var uri; + if (mQuery) { + uri = this.URI + "/" + endpoint; + } else { + uri = this.URI + "/" + orgName + "/" + appName + "/" + endpoint; + } + if (self.getToken()) { + qs.access_token = self.getToken(); + } + var developerkey = self.get("developerkey"); + if (developerkey) { + qs.key = developerkey; + } + + var isIE9 = Usergrid.browser.isIE9 = $.browser.msie && $.browser.version <= + 9; + + (isIE9) && (method === 'PUT' || method === 'DELETE') && (function() { + qs['method_override'] = method; + })(); + + //append params to the path + var encoded_params = encodeParams(qs); + if (encoded_params) { + uri += "?" + encoded_params; + } + //stringify the body object + body = options.formData ? null : JSON.stringify(body); + //so far so good, so run the query + //*** ie9 hack + var xhr; + //check to see if ie9 - if so, convert delete and put calls to a POST + if (isIE9) { //XDomainRequest + xhr = new XDomainRequest(); + (method === 'PUT' || method === 'DELETE') && (function() { + method = 'POST'; + })(); + xhr.open(method, uri); + } else { + xhr = new XMLHttpRequest(); + xhr.open(method, uri, true); + //add content type = json if there is a json payload + if (!options.formData) { + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.setRequestHeader("Accept", "application/json"); + } + } + xhr.isIE9 = isIE9; + // 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); + } + }; + 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.isIE9 && 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); + } + } else { + if (typeof callback === "function") { + callback(false, response); + } + } + }; + var timeout = setTimeout(function() { + xhr.abort(); + if (self._callTimeoutCallback === "function") { + self._callTimeoutCallback("API CALL TIMEOUT"); + } else { + callback("API CALL TIMEOUT"); + } + }, 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(options.formData || body); + }; + + Usergrid.Client.prototype.keys = function(o) { + var a = []; + for (var propertyName in o) { + a.push(propertyName); + } + return a; + } + + /* + * 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; + + var 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 || + Usergrid.browser.isIE9)) || (!err && getOnExist); + if (okToSave) { + group.save(function(err, data) { + if (typeof(callback) === 'function') { + callback(err, group); + } + }); + } 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 options = { + client:this, + data:options + } + var entity = new Usergrid.Entity(options); + entity.save(function(err, data) { + if (typeof(callback) === 'function') { + callback(err, entity); + } + }); + */ + var getOnExist = options.getOnExist || false; //if true, will return entity if one already exists + var options = { + client: this, + data: options + } + 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 + if (Usergrid.browser.isIE9 || 'service_resource_not_found' === data.error || + 'no_name_specified' === data.error || 'null_pointer' === data.error + ) { + + entity.set(options.data); //add the data again just in case + entity.save(function(err, data) { + if (typeof(callback) === 'function') { + callback(err, entity, data); + } + }); + + } else { + if (getOnExist) { + // entity exists and they want it returned + if (typeof(callback) === 'function') { + callback(err, entity, data); + } + } else { + //entity exists but they want an error to that effect + err = true; + callback(err, 'duplicate entity already exists'); + } + } + + }); + + } + + /* + * 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 + } + var entity = new Usergrid.Entity(options); + entity.fetch(function(err, data) { + if (typeof(callback) === 'function') { + 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) { + var data = JSON.parse(serializedObject); + var options = { + client: this, + data: data + } + 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" + } + + this.request(options, function(err, data) { + if (typeof(callback) === "function") { + if (err) { + callback(err); + } else { + callback(err, data, data.entities); + } + } + }); + } + + /* +* 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 entity = new Usergrid.Entity(options); + entity.save(function(err, data) { + if (typeof(callback) === 'function') { + callback(err, entity); + } + }); + } + + /* + * 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); + + } + + /* + * 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; + } + 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'); + } + + Usergrid.Client.prototype.setObject = function(key, value) { + if (value) { + value = JSON.stringify(value); + } + this.set(key, value); + } + + 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); + } + }); + } + + + 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); + } + }); + } + + + 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 = {}; + if (err && self.logging) { + console.log('error trying to full authenticate user'); + } else { + var 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); + } + }); + } + + Usergrid.Client.prototype.orgLogin = function(username, password, callback) { + var self = this; + var options = { + method: 'POST', + endpoint: 'management/token', + mQuery: true, + body: { + username: username, + password: password, + grant_type: 'password' + } + }; + this.request(options, function(err, data) { + var user = {}; + var organizations = {}; + var applications = {}; + if (err ) { + if(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); + self.set('email', data.user.email); + + + //delete next block and corresponding function when iframes are refactored + localStorage.setItem('accessToken', data.access_token); + localStorage.setItem('userUUID', data.user.uuid); + localStorage.setItem('userEmail', data.user.email); + //end delete block + + + organizations = data.user.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); + } + }); + } + + Usergrid.Client.prototype.parseApplicationsArray = function(org) { + var applications = {}; + + for (var key in org.applications) { + var uuid = org.applications[key]; + var name = key.split("/")[1]; + applications[name] = ({ + uuid: uuid, + name: name + }); + } + + return applications; + } + + Usergrid.Client.prototype.selectFirstApp = function(applications) { + try { + //try to select an app if one exists (will use existing if possible) + var existingApp = this.get('appName'); + var firstApp = Object.keys(applications)[0]; + var appName = (applications[existingApp]) ? existingApp : Object.keys( + applications)[0]; + this.set('appName', appName); + } catch (e) {} //may or may not be an application, if no, just fall through + return appName; + } + + Usergrid.Client.prototype.createApplication = function(name, callback) { + var self = this; + var options = { + method: 'POST', + endpoint: 'management/organizations/' + this.get('orgName') + + '/applications', + mQuery: true, + body: { + name: name + } + }; + this.request(options, function(err, response) { + var applications = {}; + if (err && self.logging) { + console.log('error trying to create new application'); + if (typeof(callback) === 'function') { + callback(err, applications); + } + } else { + self.getApplications(callback); + } + }); + } + + Usergrid.Client.prototype.getApplications = function(callback) { + var self = this; + var options = { + method: 'GET', + endpoint: 'management/organizations/' + this.get('orgName') + + '/applications', + mQuery: true + }; + this.request(options, function(err, data) { + /* + //grab the applications + var applicationsData = data.data; + var applicationNames = self.keys(applicationsData).sort(); + var firstApp = ''; + var applications = []; + var count = 0; + for (var i in applicationNames) { + var name = applicationNames[i]; + var uuid = applicationsData[name]; + name = name.split("/")[1]; + applications.push({uuid:uuid, name:name}); + if (count===0) { + firstApp = name; + } + count++; + } */ + + applications = self.parseApplicationsArray({ + applications: data.data + }); + self.selectFirstApp(applications); + self.setObject('applications', applications); + + if (typeof(callback) === 'function') { + callback(err, applications); + } + }); + } + + Usergrid.Client.prototype.getAdministrators = function(callback) { + var self = this; + var options = { + method: 'GET', + endpoint: 'management/organizations/' + this.get('orgName') + + '/users', + mQuery: true + }; + this.request(options, function(err, data) { + var administrators = []; + if (err) { + + } else { + var administrators = []; + for (var i in data.data) { + var admin = data.data[i]; + admin.image = self.getDisplayImage(admin.email, admin.picture); + administrators.push(admin); + } + } + + if (typeof(callback) === 'function') { + callback(err, administrators); + } + }); + } + + + Usergrid.Client.prototype.createAdministrator = function(email, callback) { + var self = this; + var options = { + method: 'POST', + endpoint: 'management/organizations/' + this.get('orgName') + + '/users', + mQuery: true, + body: { + email: email, + password: '' + } + }; + this.request(options, function(err, response) { + var admins = {}; + if (err && self.logging) { + console.log('error trying to create new administrator'); + if (typeof(callback) === 'function') { + callback(err, admins); + } + } else { + self.getAdministrators(callback); + } + }); + } + + + + /* + * A public method to log in an app user with facebook - stores the token for later use + * + * @method loginFacebook + * @public + * @params {string} username + * @params {string} password + * @param {function} callback + * @return {callback} callback(err, data) + */ + 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); + } + }); + } + + /* + * A public method to get the currently logged in user entity + * + * @method getLoggedInUser + * @public + * @param {function} callback + * @return {callback} callback(err, data) + */ + 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); + } + } + }); + } + } + + /* + * 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 + * + * @method isLoggedIn + * @public + * @return {boolean} Returns true the user is logged in (has token and uuid), false if not + */ + Usergrid.Client.prototype.isLoggedIn = function() { + if (this.getToken()) { + return true; + } + return false; + } + + /* + * A public method to log out an app user - clears all user fields from client + * + * @method logout + * @public + * @return none + */ + Usergrid.Client.prototype.logout = function() { + this.setToken(null); + this.setObject('organizations', null); + this.setObject('applications', null); + this.set('orgName', null); + this.set('appName', null); + this.set('email', null); + this.set("developerkey", null); + } + + /* + * A private method to build the curl call to display on the command line + * + * @method buildCurlCall + * @private + * @param {object} options + * @return {string} curl + */ + 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 (body !== '"{}"' && method !== 'GET' && method !== 'DELETE') { + //curl - add in the json obj + curl += " -d '" + body + "'"; + } + + //log the curl command to the console + console.log(curl); + + return curl; + } + Usergrid.Client.prototype.getDisplayImage = function(email, picture, size) { + try { + if (picture) { + return picture; + } + var size = size || 50; + if (email.length) { + return 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + + size; + } else { + return 'https://apigee.com/usergrid/img/user_profile.png'; + } + } catch (e) { + return 'https://apigee.com/usergrid/img/user_profile.png'; + } + } + + /* + * A class to Model a Usergrid Entity. + * Set the type of entity in the 'data' json object + * + * @constructor + * @param {object} options {client:client, data:{'type':'collection_type', 'key':'value'}, uuid:uuid}} + */ + Usergrid.Entity = function(options) { + if (options) { + this._data = options.data || {}; + this._client = options.client || {}; + } + }; + + /* + * returns a serialized version of the entity object + * + * Note: use the client.restoreEntity() function to restore + * + * @method serialize + * @return {string} data + */ + Usergrid.Entity.prototype.serialize = function() { + return JSON.stringify(this._data); + } + + /* + * gets a specific field or the entire data object. If null or no argument + * passed, will return all data, else, will return a specific field + * + * @method get + * @param {string} field + * @return {string} || {object} data + */ + Usergrid.Entity.prototype.get = function(field) { + if (field) { + return this._data[field]; + } else { + return this._data; + } + } + + /* + * adds a specific key value pair or object to the Entity's data + * is additive - will not overwrite existing values unless they + * are explicitly specified + * + * @method set + * @param {string} key || {object} + * @param {string} value + * @return none + */ + Usergrid.Entity.prototype.set = function(key, value) { + if (typeof key === 'object') { + for (var field in key) { + this._data[field] = key[field]; + } + } else if (typeof key === 'string') { + if (value === null) { + delete this._data[key]; + } else { + this._data[key] = value; + } + } else { + this._data = {}; + } + } + + /* + * Saves the entity back to the database + * + * @method save + * @public + * @param {function} callback + * @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(); + //remove system specific properties + for (var item in entityData) { + if (item === 'metadata' || item === 'created' || item === 'modified' || + item === 'type' || item === 'activated' || item === 'uuid') { + continue; + } + data[item] = entityData[item]; + } + var options = { + method: method, + endpoint: type, + body: data + }; + //save the entity first + this._client.request(options, function(err, retdata) { + 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); + //for connections, API returns type + self.set('type', retdata.path); + } + } + //if this is a user, update the password if it has been specified; + var needPasswordChange = (self.get('type') === 'user' && entityData + .oldpassword && entityData.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 = entityData.oldpassword; + pwdata.newpassword = entityData.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); + } + } + }); + } + + /* + * refreshes the entity by making a GET call back to the database + * + * @method fetch + * @public + * @param {function} callback + * @return {callback} callback(err, data) + */ + Usergrid.Entity.prototype.fetch = function(callback) { + var type = this.get('type'); + var self = this; + + //if a uuid is available, use that, otherwise, use the name + if (this.get('uuid')) { + type += '/' + this.get('uuid'); + } else { + if (type === 'users') { + if (this.get('username')) { + type += '/' + this.get('username'); + } else { + if (typeof(callback) === 'function') { + var error = 'no_name_specified'; + if (self._client.logging) { + console.log(error); + } + return callback(true, { + error: error + }, self) + } + } + } else if (type === 'a path') { + + ///TODO add code to deal with the type as a path + + if (this.get('path')) { + type += '/' + encodeURIComponent(this.get('name')); + } else { + if (typeof(callback) === 'function') { + var error = 'no_name_specified'; + if (self._client.logging) { + console.log(error); + } + return callback(true, { + error: error + }, self) + } + } + + } else { + if (this.get('name')) { + type += '/' + encodeURIComponent(this.get('name')); + } else { + if (typeof(callback) === 'function') { + var error = 'no_name_specified'; + if (self._client.logging) { + console.log(error); + } + return callback(true, { + error: error + }, self) + } + } + } + } + var options = { + method: 'GET', + endpoint: type + }; + 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); + } + }); + } + + /* + * deletes the entity from the database - will only delete + * if the object has a valid uuid + * + * @method destroy + * @public + * @param {function} callback + * @return {callback} callback(err, data) + * + */ + Usergrid.Entity.prototype.destroy = function(callback) { + 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 self = this; + var options = { + method: 'DELETE', + endpoint: type + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('entity could not be deleted'); + } else { + self.set(null); + } + if (typeof(callback) === 'function') { + callback(err, data); + } + }); + } + + /* + * connects one entity to another + * + * @method connect + * @public + * @param {string} connection + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data) + * + */ + Usergrid.Entity.prototype.connect = function(connection, entity, callback) { + + var self = this; + + //connectee info + var connecteeType = entity.get('type'); + var connectee = this.getEntityId(entity); + if (!connectee) { + if (typeof(callback) === 'function') { + var error = 'Error trying to delete object - no uuid specified.'; + if (self._client.logging) { + console.log(error); + } + callback(true, error); + } + return; + } + + //connector info + var connectorType = this.get('type'); + var connector = this.getEntityId(this); + if (!connector) { + if (typeof(callback) === 'function') { + var error = 'Error in connect - no uuid specified.'; + if (self._client.logging) { + console.log(error); + } + callback(true, error); + } + return; + } + + var endpoint = connectorType + '/' + connector + '/' + connection + '/' + + connecteeType + '/' + connectee; + var options = { + method: 'POST', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('entity could not be connected'); + } + if (typeof(callback) === 'function') { + callback(err, data); + } + }); + } + + /* + * returns a unique identifier for an entity + * + * @method connect + * @public + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data) + * + */ + Usergrid.Entity.prototype.getEntityId = function(entity) { + var id = false; + if (isUUID(entity.get('uuid'))) { + id = entity.get('uuid'); + } else { + if (type === 'users') { + id = entity.get('username'); + } else if (entity.get('name')) { + id = entity.get('name'); + } + } + return id; + } + + /* + * gets an entities connections + * + * @method getConnections + * @public + * @param {string} connection + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data, connections) + * + */ + Usergrid.Entity.prototype.getConnections = function(connection, callback) { + + var self = this; + + //connector info + var connectorType = this.get('type'); + var connector = this.getEntityId(this); + if (!connector) { + if (typeof(callback) === 'function') { + var error = 'Error in getConnections - no uuid specified.'; + if (self._client.logging) { + console.log(error); + } + callback(true, error); + } + return; + } + + var endpoint = connectorType + '/' + connector + '/' + connection + '/'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('entity could not be connected'); + } + + self[connection] = {}; + + var length = data.entities.length; + for (var i = 0; i < length; i++) { + if (data.entities[i].type === 'user') { + self[connection][data.entities[i].username] = data.entities[i]; + } else { + self[connection][data.entities[i].name] = data.entities[i] + } + } + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + Usergrid.Entity.prototype.getGroups = function(callback) { + + var self = this; + + var endpoint = 'users' + '/' + this.get('uuid') + '/groups'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('entity could not be connected'); + } + + self['groups'] = data.entities; + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + Usergrid.Entity.prototype.getActivities = function(callback) { + + var self = this; + + var endpoint = this.get('type') + '/' + this.get('uuid') + '/activities'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('entity could not be connected'); + } + + for (entity in data.entities) { + data.entities[entity].createdDate = (new Date(data.entities[entity] + .created)).toUTCString(); + } + + self['activities'] = data.entities; + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + Usergrid.Entity.prototype.getFollowing = function(callback) { + + var self = this; + + var endpoint = 'users' + '/' + this.get('uuid') + '/following'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('could not get user following'); + } + + for (entity in data.entities) { + data.entities[entity].createdDate = (new Date(data.entities[entity] + .created)).toUTCString(); + var image = self._client.getDisplayImage(data.entities[entity].email, + data.entities[entity].picture); + data.entities[entity]._portal_image_icon = image; + } + + self['following'] = data.entities; + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + + Usergrid.Entity.prototype.getFollowers = function(callback) { + + var self = this; + + var endpoint = 'users' + '/' + this.get('uuid') + '/followers'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('could not get user followers'); + } + + for (entity in data.entities) { + data.entities[entity].createdDate = (new Date(data.entities[entity] + .created)).toUTCString(); + var image = self._client.getDisplayImage(data.entities[entity].email, + data.entities[entity].picture); + data.entities[entity]._portal_image_icon = image; + } + + self['followers'] = data.entities; + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + Usergrid.Entity.prototype.getRoles = function(callback) { + + var self = this; + + var endpoint = this.get('type') + '/' + this.get('uuid') + '/roles'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('could not get user roles'); + } + + self['roles'] = data.entities; + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + Usergrid.Entity.prototype.getPermissions = function(callback) { + + var self = this; + + var endpoint = this.get('type') + '/' + this.get('uuid') + '/permissions'; + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('could not get user permissions'); + } + + var permissions = []; + if (data.data) { + var perms = data.data; + var count = 0; + + for (var i in perms) { + count++; + var perm = perms[i]; + var parts = perm.split(':'); + var ops_part = ""; + var path_part = parts[0]; + + if (parts.length > 1) { + ops_part = parts[0]; + path_part = parts[1]; + } + + ops_part.replace("*", "get,post,put,delete") + var ops = ops_part.split(','); + var ops_object = {} + ops_object['get'] = 'no'; + ops_object['post'] = 'no'; + ops_object['put'] = 'no'; + ops_object['delete'] = 'no'; + for (var j in ops) { + ops_object[ops[j]] = 'yes'; + } + + permissions.push({ + operations: ops_object, + path: path_part, + perm: perm + }); + } + } + + self['permissions'] = permissions; + + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + + } + + /* + * disconnects one entity from another + * + * @method disconnect + * @public + * @param {string} connection + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data) + * + */ + Usergrid.Entity.prototype.disconnect = function(connection, entity, + callback) { + + var self = this; + + //connectee info + var connecteeType = entity.get('type'); + var connectee = this.getEntityId(entity); + if (!connectee) { + if (typeof(callback) === 'function') { + var error = 'Error trying to delete object - no uuid specified.'; + if (self._client.logging) { + console.log(error); + } + callback(true, error); + } + return; + } + + //connector info + var connectorType = this.get('type'); + var connector = this.getEntityId(this); + if (!connector) { + if (typeof(callback) === 'function') { + var error = 'Error in connect - no uuid specified.'; + if (self._client.logging) { + console.log(error); + } + callback(true, error); + } + return; + } + + var endpoint = connectorType + '/' + connector + '/' + connection + '/' + + connecteeType + '/' + connectee; + var options = { + method: 'DELETE', + endpoint: endpoint + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('entity could not be disconnected'); + } + if (typeof(callback) === 'function') { + callback(err, data); + } + }); + } + + /* + * The Collection class models Usergrid Collections. It essentially + * acts as a container for holding Entity objects, while providing + * additional funcitonality such as paging, and saving + * + * @constructor + * @param {string} options - configuration object + * @param {function} callback + * @return {callback} callback(err, data) + */ + Usergrid.Collection = function(options, callback) { + + if (options) { + this._client = options.client; + this._type = options.type; + this.qs = options.qs || {}; + + //iteration + this._list = options.list || []; + this._iterator = options.iterator || -1; //first thing we do is increment, so set to -1 + + //paging + this._previous = options.previous || []; + this._next = options.next || null; + this._cursor = options.cursor || null; + + //restore entities if available + if (options.list) { + var count = options.list.length; + for (var i = 0; i < count; i++) { + //make new entity with + var entity = this._client.restoreEntity(options.list[i]); + this._list[i] = entity; + } + } + } + if (callback) { + //populate the collection + this.fetch(callback); + } + + } + + + /* + * gets the data from the collection object for serialization + * + * @method serialize + * @return {object} data + */ + Usergrid.Collection.prototype.serialize = function() { + + //pull out the state from this object and return it + var data = {} + data.type = this._type; + data.qs = this.qs; + data.iterator = this._iterator; + data.previous = this._previous; + data.next = this._next; + data.cursor = this._cursor; + + this.resetEntityPointer(); + var i = 0; + data.list = []; + while (this.hasNextEntity()) { + var entity = this.getNextEntity(); + data.list[i] = entity.serialize(); + i++; + } + + data = JSON.stringify(data); + return data; + } + + Usergrid.Collection.prototype.addCollection = function(collectionName, + options, callback) { + self = this; + options.client = this._client; + var collection = new Usergrid.Collection(options, function(err, data) { + if (typeof(callback) === 'function') { + + collection.resetEntityPointer(); + while (collection.hasNextEntity()) { + var user = collection.getNextEntity(); + var email = user.get('email'); + var image = self._client.getDisplayImage(user.get('email'), + user.get('picture')); + user._portal_image_icon = image; + } + + self[collectionName] = collection; + callback(err, collection); + } + }); + } + + /* + * Populates the collection from the server + * + * @method fetch + * @param {function} callback + * @return {callback} callback(err, data) + */ + Usergrid.Collection.prototype.fetch = function(callback) { + var self = this; + var qs = this.qs; + + //add in the cursor if one is available + if (this._cursor) { + qs.cursor = this._cursor; + } else { + delete qs.cursor; + } + var options = { + method: 'GET', + endpoint: this._type, + qs: this.qs + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('error getting collection'); + } else { + //save the cursor if there is one + var cursor = data.cursor || null; + self.saveCursor(cursor); + if (data.entities) { + self.resetEntityPointer(); + var count = data.entities.length; + //save entities locally + self._list = []; //clear the local list first + for (var i = 0; i < count; i++) { + var uuid = data.entities[i].uuid; + if (uuid) { + var entityData = data.entities[i] || {}; + self._baseType = data.entities[i].type; //store the base type in the collection + entityData.type = self._type; //make sure entities are same type (have same path) as parent collection. + var entityOptions = { + client: self._client, + data: entityData + }; + + var ent = new Usergrid.Entity(entityOptions); + ent._json = JSON.stringify(entityData, null, 2); + //if this is a user, add in an icon image + if (self._type === 'users' || self._type === 'user' || data.entities[ + i].type == 'user') { + var email = entityData.email; + var picture = entityData.picture; + var image = self._client.getDisplayImage(email, picture); + ent._portal_image_icon = image; + } + var ct = self._list.length; + self._list[ct] = ent; + } + } + } + } + if (typeof(callback) === 'function') { + callback(err, data); + } + }); + } + + /* + * Adds a new Entity to the collection (saves, then adds to the local object) + * + * @method addNewEntity + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data, entity) + */ + Usergrid.Collection.prototype.addEntity = function(options, callback) { + var self = this; + options.type = this._type; + + //create the new entity + this._client.createEntity(options, function(err, entity) { + + if (err) { + if (typeof(callback) === 'function') { + callback(err, entity); + } + } else { + + if (entity.type === '/users') { + var image = self._client.getDisplayImage(entity.email, entity.picture); + entity._portal_image_icon = image; + } + + if (!err) { + //then add the entity to the list + var count = self._list.length; + self._list[count] = entity; + } + if (typeof(callback) === 'function') { + callback(err, entity); + } + } + }); + } + + Usergrid.Collection.prototype.addExistingEntity = function(entity) { + //entity should already exist in the db, so just add it to the list + var count = this._list.length; + this._list[count] = entity; + } + + + /* + * Removes the Entity from the collection, then destroys the object on the server + * + * @method destroyEntity + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data) + */ + Usergrid.Collection.prototype.destroyEntity = function(entity, callback) { + var self = this; + entity.destroy(function(err, data) { + if (err) { + if (self._client.logging) { + console.log('could not destroy entity'); + } + if (typeof(callback) === 'function') { + callback(err, data); + } + } else { + //destroy was good, so repopulate the collection + self.fetch(callback); + } + }); + //remove entity from the local store + this.removeEntity(entity); + } + + + Usergrid.Collection.prototype.removeEntity = function(entity) { + var uuid = entity.get('uuid'); + for (key in this._list) { + var listItem = this._list[key]; + if (listItem.get('uuid') === uuid) { + return this._list.splice(key, 1); + } + } + return false; + } + + /* + * Looks up an Entity by UUID + * + * @method getEntityByUUID + * @param {string} UUID + * @param {function} callback + * @return {callback} callback(err, data, entity) + */ + Usergrid.Collection.prototype.getEntityByUUID = function(uuid, callback) { + + for (key in this._list) { + var listItem = this._list[key]; + if (listItem.get('uuid') === uuid) { + return listItem; + } + } + + //get the entity from the database + var options = { + data: { + type: this._type, + uuid: uuid + }, + client: this._client + } + var entity = new Usergrid.Entity(options); + entity.fetch(callback); + } + + /* + * Returns the first Entity of the Entity list - does not affect the iterator + * + * @method getFirstEntity + * @return {object} returns an entity object + */ + Usergrid.Collection.prototype.getFirstEntity = function() { + var count = this._list.length; + if (count > 0) { + return this._list[0]; + } + return null; + } + + /* + * Returns the last Entity of the Entity list - does not affect the iterator + * + * @method getLastEntity + * @return {object} returns an entity object + */ + Usergrid.Collection.prototype.getLastEntity = function() { + var count = this._list.length; + if (count > 0) { + return this._list[count - 1]; + } + return null; + } + + /* + * Entity iteration -Checks to see if there is a "next" entity + * in the list. The first time this method is called on an entity + * list, or after the resetEntityPointer method is called, it will + * return true referencing the first entity in the list + * + * @method hasNextEntity + * @return {boolean} true if there is a next entity, false if not + */ + Usergrid.Collection.prototype.hasNextEntity = function() { + var next = this._iterator + 1; + var hasNextElement = (next >= 0 && next < this._list.length); + if (hasNextElement) { + return true; + } + return false; + } + + /* + * Entity iteration - Gets the "next" entity in the list. The first + * time this method is called on an entity list, or after the method + * resetEntityPointer is called, it will return the, + * first entity in the list + * + * @method hasNextEntity + * @return {object} entity + */ + Usergrid.Collection.prototype.getNextEntity = function() { + this._iterator++; + var hasNextElement = (this._iterator >= 0 && this._iterator <= this._list + .length); + if (hasNextElement) { + return this._list[this._iterator]; + } + return false; + } + + /* + * Entity iteration - Checks to see if there is a "previous" + * entity in the list. + * + * @method hasPrevEntity + * @return {boolean} true if there is a previous entity, false if not + */ + Usergrid.Collection.prototype.hasPrevEntity = function() { + var previous = this._iterator - 1; + var hasPreviousElement = (previous >= 0 && previous < this._list.length); + if (hasPreviousElement) { + return true; + } + return false; + } + + /* + * Entity iteration - Gets the "previous" entity in the list. + * + * @method getPrevEntity + * @return {object} entity + */ + Usergrid.Collection.prototype.getPrevEntity = function() { + this._iterator--; + var hasPreviousElement = (this._iterator >= 0 && this._iterator <= this._list + .length); + if (hasPreviousElement) { + return this.list[this._iterator]; + } + return false; + } + + /* + * Entity iteration - Resets the iterator back to the beginning + * of the list + * + * @method resetEntityPointer + * @return none + */ + Usergrid.Collection.prototype.resetEntityPointer = function() { + this._iterator = -1; + } + + /* + * Method to save off the cursor just returned by the last API call + * + * @public + * @method saveCursor + * @return none + */ + Usergrid.Collection.prototype.saveCursor = function(cursor) { + //if current cursor is different, grab it for next cursor + if (this._next !== cursor) { + this._next = cursor; + } + } + + /* + * Resets the paging pointer (back to original page) + * + * @public + * @method resetPaging + * @return none + */ + Usergrid.Collection.prototype.resetPaging = function() { + this._previous = []; + this._next = null; + this._cursor = null; + } + + /* + * Paging - checks to see if there is a next page od data + * + * @method hasNextPage + * @return {boolean} returns true if there is a next page of data, false otherwise + */ + Usergrid.Collection.prototype.hasNextPage = function() { + return (this._next); + } + + /* + * Paging - advances the cursor and gets the next + * page of data from the API. Stores returned entities + * in the Entity list. + * + * @method getNextPage + * @param {function} callback + * @return {callback} callback(err, data) + */ + Usergrid.Collection.prototype.getNextPage = function(callback) { + if (this.hasNextPage()) { + //set the cursor to the next page of data + this._previous.push(this._cursor); + this._cursor = this._next; + //empty the list + this._list = []; + this.fetch(callback); + } + } + + /* + * Paging - checks to see if there is a previous page od data + * + * @method hasPreviousPage + * @return {boolean} returns true if there is a previous page of data, false otherwise + */ + Usergrid.Collection.prototype.hasPreviousPage = function() { + return (this._previous.length > 0); + } + + /* + * Paging - reverts the cursor and gets the previous + * page of data from the API. Stores returned entities + * in the Entity list. + * + * @method getPreviousPage + * @param {function} callback + * @return {callback} callback(err, data) + */ + Usergrid.Collection.prototype.getPreviousPage = function(callback) { + if (this.hasPreviousPage()) { + this._next = null; //clear out next so the comparison will find the next item + this._cursor = this._previous.pop(); + //empty the list + this._list = []; + this.fetch(callback); + } + } + + + /* + * A class to model a Usergrid group. + * Set the path in the options object. + * + * @constructor + * @param {object} options {client:client, data: {'key': 'value'}, path:'path'} + */ + Usergrid.Group = function(options, callback) { + this._path = options.path; + this._list = []; + this._client = options.client; + this._data = options.data || {}; + this._data.type = "groups"; + } + + /* + * Inherit from Usergrid.Entity. + * Note: This only accounts for data on the group object itself. + * You need to use add and remove to manipulate group membership. + */ + Usergrid.Group.prototype = new Usergrid.Entity(); + + /* + * Fetches current group data, and members. + * + * @method fetch + * @public + * @param {function} callback + * @returns {function} callback(err, data) + */ + Usergrid.Group.prototype.fetch = function(callback) { + var self = this; + var groupEndpoint = 'groups/' + this._path; + var memberEndpoint = 'groups/' + this._path + '/users'; + + var groupOptions = { + method: 'GET', + endpoint: groupEndpoint + } + + var memberOptions = { + method: 'GET', + endpoint: memberEndpoint + } + + this._client.request(groupOptions, function(err, data) { + if (err) { + if (self._client.logging) { + console.log('error getting group'); + } + if (typeof(callback) === 'function') { + callback(err, data); + } + } else { + if (data.entities) { + var groupData = data.entities[0]; + self._data = groupData || {}; + self._client.request(memberOptions, function(err, data) { + if (err && self._client.logging) { + console.log('error getting group users'); + } else { + if (data.entities) { + var count = data.entities.length; + self._list = []; + for (var i = 0; i < count; i++) { + var uuid = data.entities[i].uuid; + if (uuid) { + var entityData = data.entities[i] || {}; + var entityOptions = { + type: entityData.type, + client: self._client, + uuid: uuid, + data: entityData + }; + var entity = new Usergrid.Entity(entityOptions); + self._list.push(entity); + } + + } + } + } + if (typeof(callback) === 'function') { + callback(err, data, self._list); + } + }); + } + } + }); + } + + /* + * Retrieves the members of a group. + * + * @method members + * @public + * @param {function} callback + * @return {function} callback(err, data); + */ + Usergrid.Group.prototype.members = function(callback) { + if (typeof(callback) === 'function') { + callback(null, this._list); + } + } + + /* + * Adds a user to the group, and refreshes the group object. + * + * Options object: {user: user_entity} + * + * @method add + * @public + * @params {object} options + * @param {function} callback + * @return {function} callback(err, data) + */ + Usergrid.Group.prototype.add = function(options, callback) { + var self = this; + var options = { + method: "POST", + endpoint: "groups/" + this._path + "/users/" + options.user.get( + 'username') + } + + this._client.request(options, function(error, data) { + if (error) { + if (typeof(callback) === 'function') { + callback(error, data, data.entities); + } + } else { + self.fetch(callback); + } + }); + } + + /* + * Removes a user from a group, and refreshes the group object. + * + * Options object: {user: user_entity} + * + * @method remove + * @public + * @params {object} options + * @param {function} callback + * @return {function} callback(err, data) + */ + Usergrid.Group.prototype.remove = function(options, callback) { + var self = this; + + var options = { + method: "DELETE", + endpoint: "groups/" + this._path + "/users/" + options.user.get( + 'username') + } + + this._client.request(options, function(error, data) { + if (error) { + if (typeof(callback) === 'function') { + callback(error, data); + } + } else { + self.fetch(callback); + } + }); + } + + /* + * Gets feed for a group. + * + * @public + * @method feed + * @param {function} callback + * @returns {callback} callback(err, data, activities) + */ + Usergrid.Group.prototype.feed = function(callback) { + var self = this; + + var endpoint = "groups/" + this._path + "/feed"; + + var options = { + method: "GET", + endpoint: endpoint + } + + this._client.request(options, function(err, data) { + if (err && self.logging) { + console.log('error trying to log user in'); + } + if (typeof(callback) === 'function') { + callback(err, data, data.entities); + } + }); + } + + /* + * Creates activity and posts to group feed. + * + * options object: {user: user_entity, content: "activity content"} + * + * @public + * @method createGroupActivity + * @params {object} options + * @param {function} callback + * @returns {callback} callback(err, entity) + */ + Usergrid.Group.prototype.createGroupActivity = function(options, callback) { + var user = options.user; + var options = { + actor: { + "displayName": user.get("username"), + "uuid": user.get("uuid"), + "username": user.get("username"), + "email": user.get("email"), + "picture": user.get("picture"), + "image": { + "duration": 0, + "height": 80, + "url": user.get("picture"), + "width": 80 + }, + }, + "verb": "post", + "content": options.content + }; + + options.type = 'groups/' + this._path + '/activities'; + var options = { + client: this._client, + data: options + } + + var entity = new Usergrid.Entity(options); + entity.save(function(err, data) { + if (typeof(callback) === 'function') { + callback(err, entity); + } + }); + } + + /* + * Tests if the string is a uuid + * + * @public + * @method isUUID + * @param {string} uuid The string to test + * @returns {Boolean} true if string is uuid + */ + function isUUID(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}$/; + 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) { + tail = []; + var item = []; + 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)); + } + } + } + } + return tail.join("&"); + } + +})(window, sessionStorage); http://git-wip-us.apache.org/repos/asf/usergrid/blob/ada7b36b/website/content/v101-portal-demo/config.js ---------------------------------------------------------------------- diff --git a/website/content/v101-portal-demo/config.js b/website/content/v101-portal-demo/config.js deleted file mode 100644 index 82c5a0f..0000000 --- a/website/content/v101-portal-demo/config.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -var Usergrid = Usergrid || {}; - -Usergrid.showNotifcations = true; - - -// used only if hostname does not match a real server name -Usergrid.overrideUrl = 'http://localhost:8080/'; - -Usergrid.options = { - client: { - requiresDeveloperKey: false, - buildCurl: true, - logging: true - // apiKey:'123456' - }, - showAutoRefresh: true, - autoUpdateTimer: 61, //seconds - menuItems: [{ - path: '#!/org-overview', - active: true, - pic: '🕪', - title: 'Org Administration' - }, { - path: '#!/app-overview/summary', - pic: '', - title: 'App Overview' - }, { - path: '#!/users', - pic: '👤', - title: 'Users' - }, { - path: '#!/groups', - pic: '👥', - title: 'Groups' - }, { - path: '#!/roles', - pic: '', - title: 'Roles' - }, { - path: '#!/data', - pic: '📸', - title: 'Data' - }, { - path: '#!/activities', - pic: '', - title: 'Activities' - }, { - path: '#!/push/getStarted', - pic: '', - title: 'Push', - items: [{ - path: '#!/push/getStarted', - pic: '', - title: 'Get Started' - }, { - path: '#!/push/configuration', - pic: '⚒', - title: 'Configure' - }, { - path: '#!/push/history', - pic: '✇', - title: 'History' - }, { - path: '#!/push/sendNotification', - pic: '', - title: 'Send' - }] - }, - - - { - path: '#!/shell', - pic: '⌨', - title: 'Shell' - } - ] -}; - -Usergrid.regex = { - appNameRegex: new RegExp("^[0-9a-zA-Z.-]{3,25}$"), - usernameRegex: new RegExp("^[0-9a-zA-Z@\.\_-]{4,25}$"), - nameRegex: new RegExp( - "^([0-9a-zA-Z@#$%^&!?;:.,'\"~*-:+_\[\\](){}/\\ |]{3,60})+$"), - roleNameRegex: new RegExp("^([0-9a-zA-Z./-]{3,25})+$"), - emailRegex: new RegExp( - "^(([0-9a-zA-Z]+[_\+.-]?)+@[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$" - ), - passwordRegex: /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, - pathRegex: new RegExp("^/[a-zA-Z0-9\.\*_\$\{\}~-]+(\/[a-zA-Z0-9\.\*_\$\{\}~-]+)*$"), - titleRegex: new RegExp("[a-zA-Z0-9.!-?]+[\/]?"), - urlRegex: new RegExp( - "^(http?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$"), - zipRegex: new RegExp("^[0-9]{5}(?:-[0-9]{4})?$"), - countryRegex: new RegExp("^[A-Za-z ]{3,100}$"), - stateRegex: new RegExp("^[A-Za-z ]{2,100}$"), - collectionNameRegex: new RegExp("^[0-9a-zA-Z_.]{3,25}$"), - appNameRegexDescription: "This field only allows : A-Z, a-z, 0-9, dot, and dash and must be between 3-25 characters.", - usernameRegexDescription: "This field only allows : A-Z, a-z, 0-9, dot, underscore and dash. Must be between 4 and 15 characters.", - nameRegexDescription: "Please enter a valid name. Must be betwee 3 and 60 characters.", - roleNameRegexDescription: "Role only allows : /, a-z, 0-9, dot, and dash. Must be between 3 and 25 characters.", - emailRegexDescription: "Please enter a valid email.", - passwordRegexDescription: "Password must contain at least 1 upper and lower case letter, one number or special character and be at least 8 characters.", - pathRegexDescription: "Path must begin with a slash, path only allows: /, a-z, 0-9, dot, and dash, paths of the format: /path/ or /path//path are not allowed", - titleRegexDescription: "Please enter a valid title.", - urlRegexDescription: "Please enter a valid url", - zipRegexDescription: "Please enter a valid zip code.", - countryRegexDescription: "Sorry only alphabetical characters or spaces are allowed. Must be between 3-100 characters.", - stateRegexDescription: "Sorry only alphabetical characters or spaces are allowed. Must be between 2-100 characters.", - collectionNameRegexDescription: "Collection name only allows : a-z A-Z 0-9. Must be between 3-25 characters." -}; http://git-wip-us.apache.org/repos/asf/usergrid/blob/ada7b36b/website/content/v101-portal-demo/css/entypo/entypo.eot ---------------------------------------------------------------------- diff --git a/website/content/v101-portal-demo/css/entypo/entypo.eot b/website/content/v101-portal-demo/css/entypo/entypo.eot deleted file mode 100644 index d9d7326..0000000 Binary files a/website/content/v101-portal-demo/css/entypo/entypo.eot and /dev/null differ http://git-wip-us.apache.org/repos/asf/usergrid/blob/ada7b36b/website/content/v101-portal-demo/css/entypo/entypo.svg ---------------------------------------------------------------------- diff --git a/website/content/v101-portal-demo/css/entypo/entypo.svg b/website/content/v101-portal-demo/css/entypo/entypo.svg deleted file mode 100644 index e1a95c3..0000000 --- a/website/content/v101-portal-demo/css/entypo/entypo.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - http://git-wip-us.apache.org/repos/asf/usergrid/blob/ada7b36b/website/content/v101-portal-demo/css/entypo/entypo.ttf ---------------------------------------------------------------------- diff --git a/website/content/v101-portal-demo/css/entypo/entypo.ttf b/website/content/v101-portal-demo/css/entypo/entypo.ttf deleted file mode 100644 index fc305d2..0000000 Binary files a/website/content/v101-portal-demo/css/entypo/entypo.ttf and /dev/null differ http://git-wip-us.apache.org/repos/asf/usergrid/blob/ada7b36b/website/content/v101-portal-demo/css/entypo/entypo.woff ---------------------------------------------------------------------- diff --git a/website/content/v101-portal-demo/css/entypo/entypo.woff b/website/content/v101-portal-demo/css/entypo/entypo.woff deleted file mode 100644 index e744a79..0000000 Binary files a/website/content/v101-portal-demo/css/entypo/entypo.woff and /dev/null differ