http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Client.js ---------------------------------------------------------------------- diff --git a/lib/modules/Client.js b/lib/modules/Client.js new file mode 100644 index 0000000..e27ae65 --- /dev/null +++ b/lib/modules/Client.js @@ -0,0 +1,883 @@ +/* + *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. + */ +(function() { + var name = 'Client', + global = this, + overwrittenName = global[name], + exports; + var AUTH_ERRORS = [ + "auth_expired_session_token", + "auth_missing_credentials", + "auth_unverified_oath", + "expired_token", + "unauthorized", + "auth_invalid" + ]; + Usergrid.Client = function(options) { + //usergrid endpoint + 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); + } + if (options.qs) { + this.setObject('default_qs', options.qs); + } + //other options + this.buildCurl = options.buildCurl || false; + this.logging = options.logging || false; + + //timeout and callbacks + // 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 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 default_qs = this.getObject('default_qs'); + var uri; + /*var logoutCallback=function(){ + if (typeof(this.logoutCallback) === 'function') { + return this.logoutCallback(true, 'no_org_or_app_name_specified'); + } + }.bind(this);*/ + if (!mQuery && !orgName && !appName) { + return logoutCallback(); + } + if (mQuery) { + uri = this.URI + '/' + endpoint; + } else { + uri = this.URI + '/' + orgName + '/' + appName + '/' + endpoint; + } + if (this.getToken()) { + qs.access_token = this.getToken(); + /* + **NOTE** The token can also be passed as a header on the request + + xhr.setRequestHeader("Authorization", "Bearer " + self.getToken()); + xhr.withCredentials = true; + */ + } + if (default_qs) { + qs = propCopy(qs, default_qs); + } + var self=this; + var req = new Usergrid.Request(method, uri, qs, body, function(err, response) { + /*if (AUTH_ERRORS.indexOf(response.error) !== -1) { + return logoutCallback(); + }*/ + if(err){ + doCallback(callback, [err, response, self], self); + }else{ + doCallback(callback, [null, response, self], self); + } + //p.done(err, response); + }); + }; + + /* + * 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 group = new Usergrid.Group({ + path: options.path, + client: this, + data: options + }); + group.save(function(err, response) { + doCallback(callback, [err, response, group], 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) { + var entity = new Usergrid.Entity({ + client: this, + data: options + }); + entity.save(function(err, response) { + doCallback(callback, [err, response, entity], entity); + }); + }; + /* + * 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 entity = new Usergrid.Entity({ + client: this, + data: options + }); + entity.fetch(function(err, response) { + doCallback(callback, [err, response, entity], entity); + }); + }; + + /* + * 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 counters - should be called directly. + * + * options object: options {timestamp:0, category:'value', counters:{name : value}} + * + * @method createCounter + * @public + * @params {object} options + * @param {function} callback + * @return {callback} callback(err, response, counter) + */ + Usergrid.Client.prototype.createCounter = function(options, callback) { + var counter = new Usergrid.Counter({ + client: this, + data: options + }); + counter.save(callback); + }; + /* + * Main function for creating new assets - should be called directly. + * + * options object: options {name:"photo.jpg", path:"/user/uploads", "content-type":"image/jpeg", owner:"F01DE600-0000-0000-0000-000000000000", file: FileOrBlobObject } + * + * @method createCounter + * @public + * @params {object} options + * @param {function} callback + * @return {callback} callback(err, response, counter) + */ + Usergrid.Client.prototype.createAsset = function(options, callback) { + var file=options.file; + if(file){ + options.name=options.name||file.name; + options['content-type']=options['content-type']||file.type; + options.path=options.path||'/'; + delete options.file; + } + var asset = new Usergrid.Asset({ + client: this, + data: options + }); + asset.save(function(err, response, asset){ + if(file && !err){ + asset.upload(file, callback); + }else{ + doCallback(callback, [err, response, asset], asset); + } + }); + }; + + /* + * 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; + return new Usergrid.Collection(options, function(err, data, collection) { + console.log("createCollection", arguments); + doCallback(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 (err) { + doCallback(callback, [err]); + } else { + doCallback(callback, [err, data, data.getEntities()]); + } + }); + }; + + /* + * 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'; + options = { + client: this, + data: options + }; + var entity = new Usergrid.Entity(options); + entity.save(function(err, data) { + doCallback(callback, [err, data, 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; + var value = null; + if (this[key]) { + value = this[key]; + } else if (typeof(Storage) !== "undefined") { + value = localStorage.getItem(keyStore); + } + return value; + }; + + /* + * 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' + } + }; + self.request(options, function(err, response) { + var user = {}; + if (err) { + if (self.logging) console.log('error trying to log user in'); + } else { + var options = { + client: self, + data: response.user + }; + user = new Usergrid.Entity(options); + self.setToken(response.access_token); + } + doCallback(callback, [err, response, user]); + }); + }; + + Usergrid.Client.prototype.adminlogin = function(username, password, callback) { + var self = this; + var options = { + method: "POST", + endpoint:'management/token', + body: { + username: username, + password: password, + grant_type: "password" + }, + mQuery:true + }; + self.request(options, function(err, response) { + var user = {}; + if (err) { + if (self.logging) console.log("error trying to log adminuser in"); + } else { + var options = { + client: self, + data: response.user + }; + user = new Usergrid.Entity(options); + self.setToken(response.access_token); + } + doCallback(callback, [ err, response, 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.data.access_token); + + } + doCallback(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 = {}; + 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); + + } + doCallback(callback, [err, data, user, organizations, applications], self); + }); + }; + + /* + * 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); + } + doCallback(callback, [err, data, user], self); + }); + }; + + /* + * 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) { + var self = this; + if (!this.getToken()) { + doCallback(callback, [new UsergridError("Access Token not set"), null, self], self); + } else { + var options = { + method: 'GET', + endpoint: 'users/me' + }; + this.request(options, function(err, response) { + if (err) { + if (self.logging) { + console.log('error trying to log user in'); + } + console.error(err, response); + doCallback(callback, [err, response, self], self); + } else { + var options = { + client: self, + data: response.getEntity() + }; + var user = new Usergrid.Entity(options); + doCallback(callback, [null, response, user], self); + } + }); + } + }; + + /* + * 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() { + var token = this.getToken(); + return "undefined" !== typeof token && token !== null; + }; + + /* + * 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(); + }; + + /* + * A public method to destroy access tokens on the server + * + * @method logout + * @public + * @param {string} username the user associated with the token to revoke + * @param {string} token set to 'null' to revoke the token of the currently logged in user + * or set to token value to revoke a specific token + * @param {string} revokeAll set to 'true' to revoke all tokens for the user + * @return none + */ + Usergrid.Client.prototype.destroyToken = function(username, token, revokeAll, callback) { + var options = { + client: self, + method: 'PUT', + }; + + if (revokeAll === true) { + options.endpoint = 'users/' + username + '/revoketokens'; + } else if (token === null) { + options.endpoint = 'users/' + username + '/revoketoken?token=' + this.getToken(); + } else { + options.endpoint = 'users/' + username + '/revoketoken?token=' + token; + } + this.request(options, function(err, data) { + if (err) { + if (self.logging) { + console.log('error destroying access token'); + } + doCallback(callback, [err, data, null], self); + } else { + if (revokeAll === true) { + console.log('all user tokens invalidated'); + } else { + console.log('token invalidated'); + } + doCallback(callback, [err, data, null], self); + } + }); + }; + + /* + * A public method to log out an app user - clears all user fields from client + * and destroys the access token on the server. + * + * @method logout + * @public + * @param {string} username the user associated with the token to revoke + * @param {string} token set to 'null' to revoke the token of the currently logged in user + * or set to token value to revoke a specific token + * @param {string} revokeAll set to 'true' to revoke all tokens for the user + * @return none + */ + Usergrid.Client.prototype.logoutAndDestroyToken = function(username, token, revokeAll, callback) { + if (username === null) { + console.log('username required to revoke tokens'); + } else { + this.destroyToken(username, token, revokeAll, callback); + if (revokeAll === true || token === this.getToken() || token === null) { + this.setToken(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) + curl.push('-X'); + curl.push((['POST', 'PUT', 'DELETE'].indexOf(method) >= 0) ? method : 'GET'); + + //curl - append the path + curl.push(uri); + + if ("object" === typeof body && Object.keys(body).length > 0 && ['POST', 'PUT'].indexOf(method) !== -1) { + curl.push('-d'); + curl.push("'" + JSON.stringify(body) + "'"); + } + curl = curl.join(' '); + //log the curl command to the console + console.log(curl); + + return curl; + }; + + Usergrid.Client.prototype.getDisplayImage = function(email, picture, size) { + size = size || 50; + var image = 'https://apigee.com/usergrid/images/user_profile.png'; + try { + if (picture) { + image = picture; + } else if (email.length) { + image = 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png"); + } + } catch (e) { + //TODO do something with this error? + } finally { + return image; + } + }; + global[name] = Usergrid.Client; + global[name].noConflict = function() { + if (overwrittenName) { + global[name] = overwrittenName; + } + return exports; + }; + return global[name]; +}());
http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Collection.js ---------------------------------------------------------------------- diff --git a/lib/modules/Collection.js b/lib/modules/Collection.js new file mode 100644 index 0000000..d137125 --- /dev/null +++ b/lib/modules/Collection.js @@ -0,0 +1,483 @@ +/* + *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. + */ + + +/* + * 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 + * @return {Collection} collection + */ +Usergrid.Collection = function(options) { + + 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); + }*/ + +}; + + +/* + * method to determine whether or not the passed variable is a Usergrid Collection + * + * @method isCollection + * @public + * @params {any} obj - any variable + * @return {boolean} Returns true or false + */ +Usergrid.isCollection = function(obj) { + return (obj && obj instanceof Usergrid.Collection); +}; + + +/* + * 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; +}; +//addCollection is deprecated? +/*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; + doCallback(callback, [err, collection], self); + } + }); +};*/ + +/* + * 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, response) { + if (err && self._client.logging) { + console.log('error getting collection'); + } else { + //save the cursor if there is one + self.saveCursor(response.cursor || null); + self.resetEntityPointer(); + //save entities locally + self._list = response.getEntities() + .filter(function(entity) { + return isUUID(entity.uuid); + }) + .map(function(entity) { + var ent = new Usergrid.Entity({ + client: self._client + }); + ent.set(entity); + ent.type = self._type; + //ent._json = JSON.stringify(entity, null, 2); + return ent; + }); + } + doCallback(callback, [err, response, self], self); + }); +}; + +/* + * 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(entityObject, callback) { + var self = this; + entityObject.type = this._type; + + //create the new entity + this._client.createEntity(entityObject, function(err, response, entity) { + if (!err) { + //then add the entity to the list + self.addExistingEntity(entity); + } + doCallback(callback, [err, response, self], self); + }); +}; + +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, response) { + if (err) { + if (self._client.logging) { + console.log('could not destroy entity'); + } + doCallback(callback, [err, response, self], self); + } else { + //destroy was good, so repopulate the collection + self.fetch(callback); + } + //remove entity from the local store + self.removeEntity(entity); + }); +}; + +/* + * Filters the list of entities based on the supplied criteria function + * works like Array.prototype.filter + * + * @method getEntitiesByCriteria + * @param {function} criteria A function that takes each entity as an argument and returns true or false + * @return {Entity[]} returns a list of entities that caused the criteria function to return true + */ +Usergrid.Collection.prototype.getEntitiesByCriteria = function(criteria) { + return this._list.filter(criteria); +}; +/* + * Returns the first entity from the list of entities based on the supplied criteria function + * works like Array.prototype.filter + * + * @method getEntitiesByCriteria + * @param {function} criteria A function that takes each entity as an argument and returns true or false + * @return {Entity[]} returns a list of entities that caused the criteria function to return true + */ +Usergrid.Collection.prototype.getEntityByCriteria = function(criteria) { + return this.getEntitiesByCriteria(criteria).shift(); +}; +/* + * Removed an entity from the collection without destroying it on the server + * + * @method removeEntity + * @param {object} entity + * @return {Entity} returns the removed entity or undefined if it was not found + */ +Usergrid.Collection.prototype.removeEntity = function(entity) { + var removedEntity = this.getEntityByCriteria(function(item) { + return entity.uuid === item.get('uuid'); + }); + delete this._list[this._list.indexOf(removedEntity)]; + return removedEntity; +}; + +/* + * 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) { + var entity = this.getEntityByCriteria(function(item) { + return item.get('uuid') === uuid; + }); + if (entity) { + doCallback(callback, [null, entity, entity], this); + } else { + //get the entity from the database + var options = { + data: { + type: this._type, + uuid: uuid + }, + client: this._client + }; + 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); + } +}; http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Counter.js ---------------------------------------------------------------------- diff --git a/lib/modules/Counter.js b/lib/modules/Counter.js new file mode 100644 index 0000000..7b120cc --- /dev/null +++ b/lib/modules/Counter.js @@ -0,0 +1,196 @@ +/* + *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. + */ + + +/* + * A class to model a Usergrid event. + * + * @constructor + * @param {object} options {timestamp:0, category:'value', counters:{name : value}} + * @returns {callback} callback(err, event) + */ +Usergrid.Counter = function(options) { + // var self=this; + this._client = options.client; + this._data = options.data || {}; + this._data.category = options.category || "UNKNOWN"; + this._data.timestamp = options.timestamp || 0; + this._data.type = "events"; + this._data.counters = options.counters || {}; + // doCallback(callback, [false, this], this); + //this.save(callback); +}; +var COUNTER_RESOLUTIONS = [ + 'all', 'minute', 'five_minutes', 'half_hour', + 'hour', 'six_day', 'day', 'week', 'month' +]; +/* + * 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.Counter.prototype = new Usergrid.Entity(); + +/* + * overrides Entity.prototype.fetch. Returns all data for counters + * associated with the object as specified in the constructor + * + * @public + * @method increment + * @param {function} callback + * @returns {callback} callback(err, event) + */ +Usergrid.Counter.prototype.fetch = function(callback) { + this.getData({}, callback); +}; +/* + * increments the counter for a specific event + * + * options object: {name: counter_name} + * + * @public + * @method increment + * @params {object} options + * @param {function} callback + * @returns {callback} callback(err, event) + */ +Usergrid.Counter.prototype.increment = function(options, callback) { + var self = this, + name = options.name, + value = options.value; + if (!name) { + return doCallback(callback, [new UsergridInvalidArgumentError("'name' for increment, decrement must be a number"), null, self], self); + } else if (isNaN(value)) { + return doCallback(callback, [new UsergridInvalidArgumentError("'value' for increment, decrement must be a number"), null, self], self); + } else { + self._data.counters[name] = (parseInt(value)) || 1; + return self.save(callback); + } +}; +/* + * decrements the counter for a specific event + * + * options object: {name: counter_name} + * + * @public + * @method decrement + * @params {object} options + * @param {function} callback + * @returns {callback} callback(err, event) + */ + +Usergrid.Counter.prototype.decrement = function(options, callback) { + var self = this, + name = options.name, + value = options.value; + self.increment({ + name: name, + value: -((parseInt(value)) || 1) + }, callback); +}; +/* + * resets the counter for a specific event + * + * options object: {name: counter_name} + * + * @public + * @method reset + * @params {object} options + * @param {function} callback + * @returns {callback} callback(err, event) + */ + +Usergrid.Counter.prototype.reset = function(options, callback) { + var self = this, + name = options.name; + self.increment({ + name: name, + value: 0 + }, callback); +}; + +/* + * gets data for one or more counters over a given + * time period at a specified resolution + * + * options object: { + * counters: ['counter1', 'counter2', ...], + * start: epoch timestamp or ISO date string, + * end: epoch timestamp or ISO date string, + * resolution: one of ('all', 'minute', 'five_minutes', 'half_hour', 'hour', 'six_day', 'day', 'week', or 'month') + * } + * + * @public + * @method getData + * @params {object} options + * @param {function} callback + * @returns {callback} callback(err, event) + */ +Usergrid.Counter.prototype.getData = function(options, callback) { + var start_time, + end_time, + start = options.start || 0, + end = options.end || Date.now(), + resolution = (options.resolution || 'all').toLowerCase(), + counters = options.counters || Object.keys(this._data.counters), + res = (resolution || 'all').toLowerCase(); + if (COUNTER_RESOLUTIONS.indexOf(res) === -1) { + res = 'all'; + } + start_time = getSafeTime(start); + end_time = getSafeTime(end); + var self = this; + //https://api.usergrid.com/yourorgname/sandbox/counters?counter=test_counter + var params = Object.keys(counters).map(function(counter) { + return ["counter", encodeURIComponent(counters[counter])].join('='); + }); + params.push('resolution=' + res); + params.push('start_time=' + String(start_time)); + params.push('end_time=' + String(end_time)); + + var endpoint = "counters?" + params.join('&'); + this._client.request({ + endpoint: endpoint + }, function(err, data) { + if (data.counters && data.counters.length) { + data.counters.forEach(function(counter) { + self._data.counters[counter.name] = counter.value || counter.values; + }); + } + return doCallback(callback, [err, data, self], self); + }); +}; + +function getSafeTime(prop) { + var time; + switch (typeof prop) { + case "undefined": + time = Date.now(); + break; + case "number": + time = prop; + break; + case "string": + time = (isNaN(prop)) ? Date.parse(prop) : parseInt(prop); + break; + default: + time = Date.parse(prop.toString()); + } + return time; +} http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Entity.js ---------------------------------------------------------------------- diff --git a/lib/modules/Entity.js b/lib/modules/Entity.js new file mode 100644 index 0000000..029951c --- /dev/null +++ b/lib/modules/Entity.js @@ -0,0 +1,767 @@ +/* + *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 ENTITY_SYSTEM_PROPERTIES = ['metadata', 'created', 'modified', 'oldpassword', 'newpassword', 'type', 'activated', 'uuid']; + +/* + * A class to Model a Usergrid Entity. + * Set the type and uuid of entity in the 'data' json object + * + * @constructor + * @param {object} options {client:client, data:{'type':'collection_type', uuid:'uuid', 'key':'value'}} + */ +Usergrid.Entity = function(options) { + this._data={}; + this._client=undefined; + if (options) { + //this._data = options.data || {}; + this.set(options.data || {}); + this._client = options.client || {}; + } +}; + +/* + * method to determine whether or not the passed variable is a Usergrid Entity + * + * @method isEntity + * @public + * @params {any} obj - any variable + * @return {boolean} Returns true or false + */ +Usergrid.Entity.isEntity = function(obj) { + return (obj && obj instanceof Usergrid.Entity); +}; + +/* + * method to determine whether or not the passed variable is a Usergrid Entity + * That has been saved. + * + * @method isPersistedEntity + * @public + * @params {any} obj - any variable + * @return {boolean} Returns true or false + */ +Usergrid.Entity.isPersistedEntity = function(obj) { + return (isEntity(obj) && isUUID(obj.get('uuid'))); +}; + +/* + * 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(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; +}; +/* + * 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 = {}; + } +}; + +Usergrid.Entity.prototype.getEndpoint = function() { + var type = this.get('type'), + nameProperties = ['uuid', 'name'], + name; + if (type === undefined) { + throw new UsergridError('cannot fetch entity, no entity type specified', 'no_type_specified'); + } else if (/^users?$/.test(type)) { + nameProperties.unshift('username'); + } + name = this.get(nameProperties) + .filter(function(x) { + return (x !== null && "undefined" !== typeof x); + }) + .shift(); + return (name) ? [type, name].join('/') : type; +}; +/* + * Saves the entity back to the database + * + * @method save + * @public + * @param {function} callback + * @return {callback} callback(err, response, self) + */ +Usergrid.Entity.prototype.save = function(callback) { + var self = this, + type = this.get('type'), + method = 'POST', + entityId = this.get("uuid"), + changePassword, + entityData = this.get(), + options = { + method: method, + endpoint: type + }; + //update the entity if the UUID is present + if (entityId) { + options.method = 'PUT'; + options.endpoint += '/' + entityId; + } + //remove system-specific properties + options.body = Object.keys(entityData) + .filter(function(key) { + return (ENTITY_SYSTEM_PROPERTIES.indexOf(key) === -1); + }) + .reduce(function(data, key) { + data[key] = entityData[key]; + return data; + }, {}); + self._client.request(options, function(err, response) { + var entity = response.getEntity(); + if (entity) { + self.set(entity); + self.set('type', (/^\//.test(response.path)) ? response.path.substring(1) : response.path); + } + if (err && self._client.logging) { + console.log('could not save entity'); + } + doCallback(callback, [err, response, self], self); + }); +}; + +/* + * + * Updates the user's password + */ +Usergrid.Entity.prototype.changePassword = function(oldpassword, newpassword, callback) { + //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 self = this; + if ("function" === typeof oldpassword && callback === undefined) { + callback = oldpassword; + oldpassword = self.get("oldpassword"); + newpassword = self.get("newpassword"); + } + //clear out pw info if present + self.set({ + 'password': null, + 'oldpassword': null, + 'newpassword': null + }); + if ((/^users?$/.test(self.get('type'))) && oldpassword && newpassword) { + var options = { + method: 'PUT', + endpoint: 'users/' + self.get("uuid") + '/password', + body: { + uuid: self.get("uuid"), + username: self.get("username"), + oldpassword: oldpassword, + newpassword: newpassword + } + }; + self._client.request(options, function(err, response) { + 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 + doCallback(callback, [err, response, self], self); + }); + } else { + throw new UsergridInvalidArgumentError("Invalid arguments passed to 'changePassword'"); + } +}; +/* + * 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 endpoint, self = this; + endpoint = this.getEndpoint(); + var options = { + method: 'GET', + endpoint: endpoint + }; + this._client.request(options, function(err, response) { + var entity = response.getEntity(); + if (entity) { + self.set(entity); + } + doCallback(callback, [err, response, self], 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 self = this; + var endpoint = this.getEndpoint(); + + var options = { + method: 'DELETE', + endpoint: endpoint + }; + this._client.request(options, function(err, response) { + if (!err) { + self.set(null); + } + doCallback(callback, [err, response, self], self); + }); +}; + +/* + * 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) { + this.addOrRemoveConnection("POST", connection, entity, callback); +}; + +/* + * 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) { + this.addOrRemoveConnection("DELETE", connection, entity, callback); +}; +/* + * adds or removes a connection between two entities + * + * @method addOrRemoveConnection + * @public + * @param {string} method + * @param {string} connection + * @param {object} entity + * @param {function} callback + * @return {callback} callback(err, data) + * + */ +Usergrid.Entity.prototype.addOrRemoveConnection = function(method, connection, entity, callback) { + var self = this; + if (['POST', 'DELETE'].indexOf(method.toUpperCase()) == -1) { + throw new UsergridInvalidArgumentError("invalid method for connection call. must be 'POST' or 'DELETE'"); + } + //connectee info + var connecteeType = entity.get('type'); + var connectee = this.getEntityId(entity); + if (!connectee) { + throw new UsergridInvalidArgumentError("connectee could not be identified"); + } + + //connector info + var connectorType = this.get('type'); + var connector = this.getEntityId(this); + if (!connector) { + throw new UsergridInvalidArgumentError("connector could not be identified"); + } + + var endpoint = [connectorType, connector, connection, connecteeType, connectee].join('/'); + var options = { + method: method, + endpoint: endpoint + }; + this._client.request(options, function(err, response) { + if (err && self._client.logging) { + console.log('There was an error with the connection call'); + } + doCallback(callback, [err, response, self], self); + }); +}; + +/* + * 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; + if (isUUID(entity.get("uuid"))) { + id = entity.get("uuid"); + } else if (this.get("type") === "users" || this.get("type") === "user") { + id = entity.get("username"); + } else { + 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); + } + doCallback(callback, [true, error], self); + } + 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 && data.entities) ? data.entities.length : 0; + 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]; + } + } + + doCallback(callback, [err, data, data.entities], self); + }); + +}; + +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; + + doCallback(callback, [err, data, data.entities], self); + }); + +}; + +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 (var entity in data.entities) { + data.entities[entity].createdDate = (new Date(data.entities[entity].created)).toUTCString(); + } + + self.activities = data.entities; + + doCallback(callback, [err, data, data.entities], self); + }); + +}; + +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 (var 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; + + doCallback(callback, [err, data, data.entities], self); + }); + +}; + + +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 (var 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; + + doCallback(callback, [err, data, data.entities], self); + }); + +}; + +Usergrid.Client.prototype.createRole = function(roleName, permissions, callback) { + + var options = { + type: 'role', + name: roleName + }; + + this.createEntity(options, function(err, response, entity) { + if (err) { + doCallback(callback, [ err, response, self ]); + } else { + entity.assignPermissions(permissions, function (err, data) { + if (err) { + doCallback(callback, [ err, response, self ]); + } else { + doCallback(callback, [ err, data, data.data ], self); + } + }) + } + }); + +}; + +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; + doCallback(callback, [ err, data, data.entities ], self); + }); +}; + +Usergrid.Entity.prototype.assignRole = function(roleName, callback) { + + var self = this; + var type = self.get('type'); + var collection = type + 's'; + var entityID; + + if (type == 'user' && this.get('username') != null) { + entityID = self.get('username'); + } else if (type == 'group' && this.get('name') != null) { + entityID = self.get('name'); + } else if (this.get('uuid') != null) { + entityID = self.get('uuid'); + } + + if (type != 'users' && type != 'groups') { + doCallback(callback, [ new UsergridError('entity must be a group or user', 'invalid_entity_type'), null, this ], this); + } + + var endpoint = 'roles/' + roleName + '/' + collection + '/' + entityID; + var options = { + method: 'POST', + endpoint: endpoint + }; + + this._client.request(options, function(err, response) { + if (err) { + console.log('Could not assign role.'); + } + doCallback(callback, [ err, response, self ]); + }); + +}; + +Usergrid.Entity.prototype.removeRole = function(roleName, callback) { + + var self = this; + var type = self.get('type'); + var collection = type + 's'; + var entityID; + + if (type == 'user' && this.get('username') != null) { + entityID = this.get('username'); + } else if (type == 'group' && this.get('name') != null) { + entityID = this.get('name'); + } else if (this.get('uuid') != null) { + entityID = this.get('uuid'); + } + + if (type != 'users' && type != 'groups') { + doCallback(callback, [ new UsergridError('entity must be a group or user', 'invalid_entity_type'), null, this ], this); + } + + var endpoint = 'roles/' + roleName + '/' + collection + '/' + entityID; + var options = { + method: 'DELETE', + endpoint: endpoint + }; + + this._client.request(options, function(err, response) { + if (err) { + console.log('Could not assign role.'); + } + doCallback(callback, [ err, response, self ]); + }); + +}; + +Usergrid.Entity.prototype.assignPermissions = function(permissions, callback) { + var self = this; + var entityID; + var type = this.get('type'); + + if (type != 'user' && type != 'users' && type != 'group' && type != 'groups' && type != 'role' && type != 'roles') { + doCallback(callback, [ new UsergridError('entity must be a group, user, or role', 'invalid_entity_type'), null, this ], this); + } + + if (type == 'user' && this.get('username') != null) { + entityID = this.get('username'); + } else if (type == 'group' && this.get('name') != null) { + entityID = this.get('name'); + } else if (this.get('uuid') != null) { + entityID = this.get('uuid'); + } + + var endpoint = type + '/' + entityID + '/permissions'; + var options = { + method: 'POST', + endpoint: endpoint, + body: { + 'permission': permissions + } + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('could not assign permissions'); + } + doCallback(callback, [ err, data, data.data ], self); + }); +}; + +Usergrid.Entity.prototype.removePermissions = function(permissions, callback) { + var self = this; + var entityID; + var type = this.get('type'); + + if (type != 'user' && type != 'users' && type != 'group' && type != 'groups' && type != 'role' && type != 'roles') { + doCallback(callback, [ new UsergridError('entity must be a group, user, or role', 'invalid_entity_type'), null, this ], this); + } + + if (type == 'user' && this.get('username') != null) { + entityID = this.get('username'); + } else if (type == 'group' && this.get('name') != null) { + entityID = this.get('name'); + } else if (this.get('uuid') != null) { + entityID = this.get('uuid'); + } + + var endpoint = type + '/' + entityID + '/permissions'; + var options = { + method: 'DELETE', + endpoint: endpoint, + qs: { + 'permission': permissions + } + }; + this._client.request(options, function(err, data) { + if (err && self._client.logging) { + console.log('could not remove permissions'); + } + doCallback(callback, [ err, data, data.params.permission ], self); + }); +}; + +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=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; + + doCallback(callback, [err, data, data.entities], self); + }); + +}; http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Error.js ---------------------------------------------------------------------- diff --git a/lib/modules/Error.js b/lib/modules/Error.js new file mode 100644 index 0000000..5cc5807 --- /dev/null +++ b/lib/modules/Error.js @@ -0,0 +1,155 @@ +/* + *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. + */ +//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 || 'invalid_http_method'; + 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 || 'invalid_uri'; + this.timestamp = timestamp || Date.now(); + this.duration = duration || 0; + this.exception = exception; + } + UsergridInvalidURIError.prototype = new UsergridError(); + + function UsergridInvalidArgumentError(message, name, timestamp, duration, exception) { + this.message = message; + this.name = name || 'invalid_argument'; + this.timestamp = timestamp || Date.now(); + this.duration = duration || 0; + this.exception = exception; + } + UsergridInvalidArgumentError.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.UsergridInvalidArgumentError = UsergridInvalidArgumentError; + 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)); http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Folder.js ---------------------------------------------------------------------- diff --git a/lib/modules/Folder.js b/lib/modules/Folder.js new file mode 100644 index 0000000..9d13155 --- /dev/null +++ b/lib/modules/Folder.js @@ -0,0 +1,190 @@ +/* + *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. + */ + +/* + * A class to model a Usergrid folder. + * + * @constructor + * @param {object} options {name:"MyPhotos", path:"/user/uploads", owner:"00000000-0000-0000-0000-000000000000" } + * @returns {callback} callback(err, folder) + */ +Usergrid.Folder = function(options, callback) { + var self = this, + messages = []; + console.log("FOLDER OPTIONS", options); + self._client = options.client; + self._data = options.data || {}; + self._data.type = "folders"; + var missingData = ["name", "owner", "path"].some(function(required) { + return !(required in self._data); + }); + if (missingData) { + return doCallback(callback, [new UsergridInvalidArgumentError("Invalid asset data: 'name', 'owner', and 'path' are required properties."), null, self], self); + } + self.save(function(err, response) { + if (err) { + doCallback(callback, [new UsergridError(response), response, self], self); + } else { + if (response && response.entities && response.entities.length) { + self.set(response.entities[0]); + } + doCallback(callback, [null, response, self], self); + } + }); +}; +/* + * Inherit from Usergrid.Entity. + */ +Usergrid.Folder.prototype = new Usergrid.Entity(); + + +/* + * fetch the folder and associated assets + * + * @method fetch + * @public + * @param {function} callback(err, self) + * @returns {callback} callback(err, self) + */ +Usergrid.Folder.prototype.fetch = function(callback) { + var self = this; + Usergrid.Entity.prototype.fetch.call(self, function(err, data) { + console.log("self", self.get()); + console.log("data", data); + if (!err) { + self.getAssets(function(err, response) { + if (err) { + doCallback(callback, [new UsergridError(response), resonse, self], self); + } else { + doCallback(callback, [null, self], self); + } + }); + } else { + doCallback(callback, [null, data, self], self); + } + }); +}; +/* + * Add an asset to the folder. + * + * @method addAsset + * @public + * @param {object} options {asset:(uuid || Usergrid.Asset || {name:"photo.jpg", path:"/user/uploads", "content-type":"image/jpeg", owner:"F01DE600-0000-0000-0000-000000000000" }) } + * @returns {callback} callback(err, folder) + */ +Usergrid.Folder.prototype.addAsset = function(options, callback) { + var self = this; + if (('asset' in options)) { + var asset = null; + switch (typeof options.asset) { + case 'object': + asset = options.asset; + if (!(asset instanceof Usergrid.Entity)) { + asset = new Usergrid.Asset(asset); + } + break; + case 'string': + if (isUUID(options.asset)) { + asset = new Usergrid.Asset({ + client: self._client, + data: { + uuid: options.asset, + type: "assets" + } + }); + } + break; + } + if (asset && asset instanceof Usergrid.Entity) { + asset.fetch(function(err, data) { + if (err) { + doCallback(callback, [new UsergridError(data), data, self], self); + } else { + var endpoint = ["folders", self.get("uuid"), "assets", asset.get("uuid")].join('/'); + var options = { + method: 'POST', + endpoint: endpoint + }; + self._client.request(options, callback); + } + }); + } + } else { + //nothing to add + doCallback(callback, [new UsergridInvalidArgumentError("No asset specified"), null, self], self); + } +}; + +/* + * Remove an asset from the folder. + * + * @method removeAsset + * @public + * @param {object} options {asset:(uuid || Usergrid.Asset || {name:"photo.jpg", path:"/user/uploads", "content-type":"image/jpeg", owner:"F01DE600-0000-0000-0000-000000000000" }) } + * @returns {callback} callback(err, folder) + */ +Usergrid.Folder.prototype.removeAsset = function(options, callback) { + var self = this; + if (('asset' in options)) { + var asset = null; + switch (typeof options.asset) { + case 'object': + asset = options.asset; + break; + case 'string': + if (isUUID(options.asset)) { + asset = new Usergrid.Asset({ + client: self._client, + data: { + uuid: options.asset, + type: "assets" + } + }); + } + break; + } + if (asset && asset !== null) { + var endpoint = ["folders", self.get("uuid"), "assets", asset.get("uuid")].join('/'); + self._client.request({ + method: 'DELETE', + endpoint: endpoint + }, function(err, response) { + if (err) { + doCallback(callback, [new UsergridError(response), response, self], self); + } else { + doCallback(callback, [null, response, self], self); + } + }); + } + } else { + //nothing to add + doCallback(callback, [new UsergridInvalidArgumentError("No asset specified"), null, self], self); + } +}; + +/* + * List the assets in the folder. + * + * @method getAssets + * @public + * @returns {callback} callback(err, assets) + */ +Usergrid.Folder.prototype.getAssets = function(callback) { + return this.getConnections("assets", callback); +}; http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/lib/modules/Group.js ---------------------------------------------------------------------- diff --git a/lib/modules/Group.js b/lib/modules/Group.js new file mode 100644 index 0000000..1ea27c2 --- /dev/null +++ b/lib/modules/Group.js @@ -0,0 +1,231 @@ +/* + *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. + */ + + +/* + * 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, response) { + if (err) { + if (self._client.logging) { + console.log('error getting group'); + } + doCallback(callback, [err, response], self); + } else { + var entities = response.getEntities(); + if (entities && entities.length) { + var groupresponse = entities.shift(); + //self._response = groupresponse || {}; + self._client.request(memberOptions, function(err, response) { + if (err && self._client.logging) { + console.log('error getting group users'); + } else { + self._list = response.getEntities() + .filter(function(entity) { + return isUUID(entity.uuid); + }) + .map(function(entity) { + return new Usergrid.Entity({ + type: entity.type, + client: self._client, + uuid: entity.uuid, + response: entity //TODO: deprecate this property + }); + }); + } + doCallback(callback, [err, response, self], self); + }); + } + } + }); +}; + +/* + * Retrieves the members of a group. + * + * @method members + * @public + * @param {function} callback + * @return {function} callback(err, data); + */ +Usergrid.Group.prototype.members = function(callback) { + //doCallback(callback, [null, this._list, this], this); + return this._list; +}; + +/* + * Adds an existing 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; + if (options.user) { + options = { + method: "POST", + endpoint: "groups/" + this._path + "/users/" + options.user.get('username') + }; + this._client.request(options, function(error, response) { + if (error) { + doCallback(callback, [error, response, self], self); + } else { + self.fetch(callback); + } + }); + } else { + doCallback(callback, [new UsergridError("no user specified", 'no_user_specified'), null, this], this); + } +}; + +/* + * 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; + if (options.user) { + options = { + method: "DELETE", + endpoint: "groups/" + this._path + "/users/" + options.user.username + }; + this._client.request(options, function(error, response) { + if (error) { + doCallback(callback, [error, response, self], self); + } else { + self.fetch(callback); + } + }); + } else { + doCallback(callback, [new UsergridError("no user specified", 'no_user_specified'), null, this], this); + } +}; + +/* + * 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 options = { + method: "GET", + endpoint: "groups/" + this._path + "/feed" + }; + this._client.request(options, function(err, response) { + doCallback(callback, [err, response, self], self); + }); +}; + +/* + * 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 self = this; + var user = options.user; + var entity = new Usergrid.Entity({ + client: this._client, + data: { + 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, + "type": 'groups/' + this._path + '/activities' + } + }); + entity.save(function(err, response, entity) { + doCallback(callback, [err, response, self]); + }); +};
