From 3aab2e62cc43dbf628145d9ecaf328a71ef74889 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 10:56:21 +0200 Subject: [PATCH 01/15] Fixes some lint errors --- lib/Parse.js | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index a384836..bafdb81 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -5,7 +5,7 @@ qs.escape = function(q){ return q; }; module.exports = Parse; function Parse(options_or_application_id, master_key) { - this._options = {} + this._options = {}; if (master_key) { this._options.app_id = options_or_application_id; this._options.master_key = master_key; @@ -44,14 +44,14 @@ Parse.prototype = { // if only 3 arguments exist, third argument is the callback, order and limit are undefined if (arguments.length === 3) { - var callback = order; - var order = undefined; - var limit = 9999; + callback = order; + order = undefined; + limit = 9999; } // if only 5 arguments exist, fifth argument is the callback, skip is undefined if (arguments.length === 5) { - var callback = skip; + callback = skip; skip = undefined; } @@ -76,9 +76,9 @@ Parse.prototype = { // get an object belonging to a certain User getFileByUser: function(userId, className, callback) { - queryString = 'where={"user":' + '"' + userId + '"' + '}' + queryString = 'where={"user":' + '"' + userId + '"' + '}'; encodedString = encodeURIComponent(queryString); - parseRequest.call(this, 'GET', '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/1/classes/' + className + '?' + encodedString, null, callback) + parseRequest.call(this, 'GET', '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/1/classes/' + className + '?' + encodedString, null, callback); }, // insert an object into Parse @@ -93,20 +93,20 @@ Parse.prototype = { // update a User object's email address updateUserEmail: function(objectId, data, callback) { - data = { email: data } - parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback) + data = { email: data }; + parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); }, // update a User object's username* updateUserName: function(objectId, data, callback) { - data = { username: data } - parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback) + data = { username: data }; + parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); }, // reset a User object's password passwordReset: function (data, callback) { - data = { email: data } - parseRequest.call(this, 'POST', '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/1/requestPasswordReset/', data, callback) + data = { email: data }; + parseRequest.call(this, 'POST', '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/1/requestPasswordReset/', data, callback); }, // remove an object from the class store @@ -117,40 +117,40 @@ Parse.prototype = { // upload installation data insertInstallationData: function (deviceType, deviceToken, callback) { if (deviceType === 'ios'){ - data = { deviceType: deviceType, deviceToken: deviceToken } + data = { deviceType: deviceType, deviceToken: deviceToken }; } else { - data = { deviceType: deviceType, installationId: deviceToken } + data = { deviceType: deviceType, installationId: deviceToken }; } parseRequest.call(this, 'POST', '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/1/installations/', data, callback); }, insertInstallationDataWithTimeZone: function (deviceType, deviceToken, timeZone, callback) { if (deviceType === 'ios'){ - data = { deviceType: deviceType, deviceToken: deviceToken, timeZone: timeZone } + data = { deviceType: deviceType, deviceToken: deviceToken, timeZone: timeZone }; } else { - data = { deviceType: deviceType, installationId: deviceToken, timeZone: timeZone } + data = { deviceType: deviceType, installationId: deviceToken, timeZone: timeZone }; } parseRequest.call(this, 'POST', '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/1/installations/', data, callback); }, insertInstallationDataWithChannels: function (deviceType, deviceToken, channels, callback) { if (deviceType === 'ios'){ - data = { deviceType: deviceType, deviceToken: deviceToken, channels: channels } + data = { deviceType: deviceType, deviceToken: deviceToken, channels: channels }; } else { - data = { deviceType: deviceType, installationId: deviceToken, channels: channels } + data = { deviceType: deviceType, installationId: deviceToken, channels: channels }; } parseRequest.call(this, 'POST', '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/1/installations/', data, callback); }, insertInstallationDataWithTimeZoneAndChannels: function (deviceType, deviceToken, timeZone, channels, callback) { if (deviceType === 'ios'){ - data = { deviceType: deviceType, deviceToken: deviceToken, timeZone: timeZone, channels: channels } + data = { deviceType: deviceType, deviceToken: deviceToken, timeZone: timeZone, channels: channels }; } else { - data = { deviceType: deviceType, installationId: deviceToken, timeZone: timeZone, channels: channels } + data = { deviceType: deviceType, installationId: deviceToken, timeZone: timeZone, channels: channels }; } parseRequest.call(this, 'POST', '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/1/installations/', data, callback); }, @@ -192,13 +192,13 @@ Parse.prototype = { }, addRelation: function( relationName, className1, objectId1, className2, objectId2, callback) { - data = {} + data = {}; data[relationName] = { __op:"AddRelation",objects:[{__type:"Pointer",className:className2,objectId:objectId2}]}; parseRequest.call(this,'PUT','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/1/classes/' + className1+'/'+objectId1,data,callback); }, removeRelation: function( relationName, className1, objectId1, className2, objectId2, callback) { - data = {} + data = {}; data[relationName] = { __op:"RemoveRelation",objects:[{__type:"Pointer",className:className2,objectId:objectId2}]}; parseRequest.call(this,'PUT','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/1/classes/' + className1+'/'+objectId1,data,callback); }, @@ -345,6 +345,6 @@ function toDeleteOps(className, objects){ method: 'DELETE', path: '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/1/classes/' + className + '/' + object.objectId, body: {} - } + }; }); } From 73a0046d523fa89c6294a4f74abc489384ea56bc Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 11:08:47 +0200 Subject: [PATCH 02/15] Uses Parse error object instead of custom error Parse error object contains more information about what went wrong --- lib/Parse.js | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index bafdb81..20bbf9d 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -296,19 +296,6 @@ function parseRequest(method, path, data, callback, contentType) { return; } - if (res.statusCode < 200 || res.statusCode >= 300) { - var err = new Error('HTTP error ' + res.statusCode); - err.arguments = arguments; - err.type = res.statusCode; - err.options = options; - err.body = body; - return callback(err); - } - - // if ((!err) && (res.statusCode === 200 || res.statusCode === 201)) { - // res.success = res.statusCode; - // } - var json = ''; res.setEncoding('utf8'); @@ -317,13 +304,17 @@ function parseRequest(method, path, data, callback, contentType) { }); res.on('end', function () { - var err = null; - var data = null; + var data; try { - var data = JSON.parse(json); - } catch (err) { + data = JSON.parse(json); + if ( data.code ) { + throw (data); + } + callback(null, data); + } + catch (err) { + callback(err); } - callback(err, data); }); res.on('close', function (err) { From 8df6d3b0b8f3fc38785294d014d5fc19e33fac2c Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 11:26:30 +0200 Subject: [PATCH 03/15] Removes unnecessary lines Fall-through takes care of it, post and put have identical headers --- lib/Parse.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index 20bbf9d..9736531 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -269,8 +269,6 @@ function parseRequest(method, path, data, callback, contentType) { } break; case 'POST': - body = typeof data === 'object' ? JSON.stringify(data) : data; - headers['Content-length'] = Buffer.byteLength(body); case 'PUT': body = typeof data === 'object' ? JSON.stringify(data) : data; headers['Content-length'] = Buffer.byteLength(body); From 70956a33c3560a1ab059d22b4373f76f756ee028 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 11:26:53 +0200 Subject: [PATCH 04/15] Adds support for buffered files --- lib/Parse.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index 9736531..a54ebbb 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -270,8 +270,10 @@ function parseRequest(method, path, data, callback, contentType) { break; case 'POST': case 'PUT': - body = typeof data === 'object' ? JSON.stringify(data) : data; - headers['Content-length'] = Buffer.byteLength(body); + body = contentType ? data : typeof data === 'object' ? JSON.stringify(data) : data; + if ( !contentType ) { + headers['Content-length'] = Buffer.byteLength(body); + } headers['Content-type'] = contentType || 'application/json'; break; case 'DELETE': From b44902ce452ae5b099c31962d37ffeda69412137 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 11:46:18 +0200 Subject: [PATCH 05/15] Adds contributors If they worked on it they should be added as contributors, right? No idea if I got everyone --- package.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f665eb5..915e6d7 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,21 @@ "author": "Chris Johnson , Michael Leveton , Seth Gholson", "contributors": [ "Daniel Gasienica ", - "Jakub Knejzlík" + "Jakub Knejzlík", + "Sam Saccone", + "Arnaud Rinquin", + "Charles Julian Knight", + "Barrington Haynes", + "Christian Monaghan", + "Christoffer Niska", + "Rodrigo Martell", + "Joe Bruggeman", + "Omar A", + "Andrey", + "Rafael Galdêncio", + "Akhmad Fathonih", + "Kody J. Peterson", + "Jo Jordens" ], "main": "index", "scripts": { From 388956cce50f7a555024dd7f3e9e5ddc6d8ef26b Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 13:13:19 +0200 Subject: [PATCH 06/15] Adds insertUser and updateUser insertUser: create new users updateUser: update keys other than username and email --- lib/Parse.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/Parse.js b/lib/Parse.js index a54ebbb..cec74af 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -29,6 +29,11 @@ Parse.prototype = { parseRequest.call(this, 'POST', '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/1/files/' + fileName, data, callback, contentType); }, + // create a new user + insertUser: function (data, callback) { + parseRequest.call(this, 'POST', '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/1/users/', data, callback); + }, + // get an object from the class store find: function (className, query, callback) { if (typeof query === 'string') { @@ -103,6 +108,11 @@ Parse.prototype = { parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); }, + // update any keys of a User object + updateUser: function (objectId, data, callback) { + parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); + }, + // reset a User object's password passwordReset: function (data, callback) { data = { email: data }; From 902f096f52592811d342446e1d79906198822a8a Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 16:31:46 +0200 Subject: [PATCH 07/15] Optimizes find The 'find' method can now be used to find a single object as well as many objects with every combination of query constraints that Parse allows. findMany is now deprecated --- lib/Parse.js | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index cec74af..530983e 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -36,37 +36,59 @@ Parse.prototype = { // get an object from the class store find: function (className, query, callback) { - if (typeof query === 'string') { - parseRequest.call(this, 'GET', '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/1/classes/' + className + '/' + query, null, callback); - } else { - parseRequest.call(this, 'GET', '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/1/classes/' + className, { where: JSON.stringify(query) }, callback); + var url = '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/1/classes/' + className; + var queryType = typeof query; + if ( queryType === 'string' ) { + url += '/' + query; + } else if ( queryType === 'object' ) { + + // if the user wants to add 'include' or 'key' (or other types of) constraints while getting only one object + // objectId can be added to the query object and is deleted after it's appended to the url + if ( query.hasOwnProperty('objectId') ) { + url += '/' + query.objectId; + delete query.objectId; + } + + // check to see if there is a 'where' object in the query object + // the 'where' object need to be stringified by JSON.stringify(), not querystring + if ( query.hasOwnProperty('where') ) { + url += '?where=' + JSON.stringify(query.where); + delete query.where; + } + + // if there are no more constraints left in the query object 'remainingQuery' will be an empty string + var remainingQuery = qs.stringify(query); + if ( remainingQuery ) { + url += ( url.indexOf('?') === -1 ? '?' : '&' ) + remainingQuery; + } + } + parseRequest.call(this, 'GET', url, null, callback); }, // get a collection of objects findMany: function (className, query, order, limit, skip, callback) { - // also supports the following api - findMany: function (className, query, callback) + console.warn('"findMany" is deprecated, use "find" instead.'); // if only 3 arguments exist, third argument is the callback, order and limit are undefined if (arguments.length === 3) { callback = order; - order = undefined; - limit = 9999; } // if only 5 arguments exist, fifth argument is the callback, skip is undefined if (arguments.length === 5) { + query.order = order; + query.limit = limit; callback = skip; - skip = undefined; } - if (typeof(query) === 'string') { - parseRequest.call(this, 'GET', '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/1/classes/' + className + '/' + query, null, callback); - } else if (skip !== undefined) { - parseRequest.call(this, 'GET', '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/1/classes/' + className, { limit: limit, order:order, skip:skip, where: JSON.stringify(query) }, callback); - } else { - parseRequest.call(this, 'GET', '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/1/classes/' + className, { limit: limit, order:order, where: JSON.stringify(query) }, callback); + if ( arguments.length === 6 ) { + query.order = order; + query.limit = limit; + query.skip = skip; } + + this.find(className, query, callback); }, // do a batch of requests at once From 454dc172b39121c2479f892fd7bfc9003197321a Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Tue, 21 Apr 2015 16:52:43 +0200 Subject: [PATCH 08/15] Adds method to retrieve user object content Adds a method to retrieve content of one or more user objects. Retrieving user data is identical to "find" except for the url (granted '/1/classes/_User' works too but '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/1/users' is the proper way to do it). Previous getUser method is now replaced by loginUser. --- lib/Parse.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index 530983e..b4f2bbc 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -36,7 +36,7 @@ Parse.prototype = { // get an object from the class store find: function (className, query, callback) { - var url = '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/1/classes/' + className; + var url = '/1/' + (className === '_User' ? 'users' : 'classes/' + className); var queryType = typeof query; if ( queryType === 'string' ) { url += '/' + query; @@ -68,7 +68,7 @@ Parse.prototype = { // get a collection of objects findMany: function (className, query, order, limit, skip, callback) { - console.warn('"findMany" is deprecated, use "find" instead.'); + console.warn('"findMany" is deprecated, please use "find" instead.'); // if only 3 arguments exist, third argument is the callback, order and limit are undefined if (arguments.length === 3) { @@ -96,9 +96,20 @@ Parse.prototype = { parseRequest.call(this,'POST','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/1/batch',{requests:requests},callback); }, - // get a user from the Parse's special User class. See https://parse.com/questions/why-does-querying-for-a-user-create-a-second-user-class - getUser: function (userName, passWord, callback) { - parseRequest.call(this, 'GET', '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/1/login/?username=' + userName + '&password=' + passWord, null, callback); + // user login + loginUser: function (username, password, callback) { + parseRequest.call(this, 'GET', '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/1/login/?username=' + username + '&password=' + password, null, callback); + }, + + // retrieve contents of one or more user objects + getUser: function (query, callback, deprecatedCallback) { + if ( arguments.length === 3 ) { + console.warn('Logging in with "getUser" is deprecated, please use loginUser instead.'); + console.warn('Use "getUser" to retrieve one or more user object contents without logging in.'); + this.loginUser(query, callback, deprecatedCallback); + } else { + this.find('_User', query, callback); + } }, // get an object belonging to a certain User From e5d30883bfeb0f6f44be79336978d84b083733be Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Wed, 22 Apr 2015 10:49:29 +0200 Subject: [PATCH 09/15] Replaces if-blocks with switch --- lib/Parse.js | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index b4f2bbc..042a87f 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -70,22 +70,18 @@ Parse.prototype = { findMany: function (className, query, order, limit, skip, callback) { console.warn('"findMany" is deprecated, please use "find" instead.'); - // if only 3 arguments exist, third argument is the callback, order and limit are undefined - if (arguments.length === 3) { - callback = order; - } - - // if only 5 arguments exist, fifth argument is the callback, skip is undefined - if (arguments.length === 5) { - query.order = order; - query.limit = limit; - callback = skip; - } - - if ( arguments.length === 6 ) { - query.order = order; - query.limit = limit; - query.skip = skip; + switch ( arguments.length ) { + case 3: callback = order; + break; + case 5: query.order = order; + query.limit = limit; + callback = skip; + break; + case 6: query.order = order; + query.limit = limit; + query.skip = skip; + break; + default: throw new Error('Unexpected number of arguments'); } this.find(className, query, callback); From 28ac73ac7774f70c02206b643e0d8e7c590c9c78 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Wed, 22 Apr 2015 11:22:45 +0200 Subject: [PATCH 10/15] Adds support for sessionToken Session tokens only work with the rest api key. While using the master key you can edit all data anyway. --- lib/Parse.js | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index 042a87f..d75851a 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -81,7 +81,7 @@ Parse.prototype = { query.limit = limit; query.skip = skip; break; - default: throw new Error('Unexpected number of arguments'); + default: throw new Error('Unexpected number of arguments.'); } this.find(className, query, callback); @@ -97,11 +97,16 @@ Parse.prototype = { parseRequest.call(this, 'GET', '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/1/login/?username=' + username + '&password=' + password, null, callback); }, + // retrieve current user + me: function (sessionToken, callback) { + parseRequest.call(this, 'GET', '/1/users/me', null, callback, null, sessionToken); + }, + // retrieve contents of one or more user objects getUser: function (query, callback, deprecatedCallback) { if ( arguments.length === 3 ) { console.warn('Logging in with "getUser" is deprecated, please use loginUser instead.'); - console.warn('Use "getUser" to retrieve one or more user object contents without logging in.'); + console.warn('Use "getUser" to retrieve one or more user object contents.'); this.loginUser(query, callback, deprecatedCallback); } else { this.find('_User', query, callback); @@ -126,20 +131,29 @@ Parse.prototype = { }, // update a User object's email address - updateUserEmail: function(objectId, data, callback) { + updateUserEmail: function(objectId, data, sessionToken, callback) { + if ( arguments.length !== 4 ) { + throw new Error('Unexpected number of arguments.'); + } data = { email: data }; - parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); + parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback, null, sessionToken); }, // update a User object's username* - updateUserName: function(objectId, data, callback) { + updateUserName: function(objectId, data, sessionToken, callback) { + if ( arguments.length !== 4 ) { + throw new Error('Unexpected number of arguments.'); + } data = { username: data }; - parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); + parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback, null, sessionToken); }, // update any keys of a User object - updateUser: function (objectId, data, callback) { - parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback); + updateUser: function (objectId, data, sessionToken, callback) { + if ( arguments.length !== 4 ) { + throw new Error('Unexpected number of arguments.'); + } + parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback, null, sessionToken); }, // reset a User object's password @@ -285,7 +299,7 @@ Parse.prototype = { }; // Parse.com https api request -function parseRequest(method, path, data, callback, contentType) { +function parseRequest(method, path, data, callback, contentType, sessionToken) { var headers = { Connection: 'Keep-alive' }; @@ -293,9 +307,15 @@ function parseRequest(method, path, data, callback, contentType) { if(this._options.master_key){ var auth = 'Basic ' + new Buffer(this._options.app_id + ':' + this._options.master_key).toString('base64'); headers.Authorization = auth; + if ( sessionToken ) { + throw new Error('Can\'t use session tokens while using the master key.'); + } }else if(this._options.api_key){ headers['X-Parse-Application-Id'] = this._options.app_id; headers['X-Parse-REST-API-Key'] = this._options.api_key; + if ( sessionToken ) { + headers['X-Parse-Session-Token'] = sessionToken; + } } From ee86d7b99fdad5c16ab86ea7d7810f0a062cf497 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Thu, 23 Apr 2015 10:32:32 +0200 Subject: [PATCH 11/15] Adds deleteUser and deleteAllUsers methods --- lib/Parse.js | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index d75851a..fc72423 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -68,7 +68,7 @@ Parse.prototype = { // get a collection of objects findMany: function (className, query, order, limit, skip, callback) { - console.warn('"findMany" is deprecated, please use "find" instead.'); + console.warn('"findMany" is deprecated, use "find" instead.'); switch ( arguments.length ) { case 3: callback = order; @@ -105,7 +105,7 @@ Parse.prototype = { // retrieve contents of one or more user objects getUser: function (query, callback, deprecatedCallback) { if ( arguments.length === 3 ) { - console.warn('Logging in with "getUser" is deprecated, please use loginUser instead.'); + console.warn('Logging in with "getUser" is deprecated, use loginUser instead.'); console.warn('Use "getUser" to retrieve one or more user object contents.'); this.loginUser(query, callback, deprecatedCallback); } else { @@ -167,6 +167,27 @@ Parse.prototype = { parseRequest.call(this, 'DELETE', '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/1/classes/' + className + '/' + objectId, null, callback); }, + // remove an object from the class store + deleteUser: function (objectId, callback) { + parseRequest.call(this, 'DELETE', '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/1/users/' + objectId, null, callback); + }, + + deleteAll: function(className, callback){ + var that = this; + this.find(className, '', function (err, response) { + var requests = toDeleteOps(className, response.results); + that.batch(requests, callback); + }); + }, + + deleteAllUsers: function(callback){ + var that = this; + this.find('_User', '', function (err, response) { + var requests = toDeleteOps('_User', response.results); + that.batch(requests, callback); + }); + }, + // upload installation data insertInstallationData: function (deviceType, deviceToken, callback) { if (deviceType === 'ios'){ @@ -287,14 +308,6 @@ Parse.prototype = { sendPush: function (data, callback) { parseRequest.call(this, 'POST', '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/1/push/', data, callback); - }, - - deleteAll: function(modelName, callback){ - var that = this; - this.findMany(modelName, '', function(err, response){ - var requests = toDeleteOps(modelName, response.results); - that.batch(requests, callback); - }); } }; @@ -393,8 +406,7 @@ function toDeleteOps(className, objects){ return objects.map(function(object){ return { method: 'DELETE', - path: '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/1/classes/' + className + '/' + object.objectId, - body: {} + path: '/1/' + ( className === '_User' ? 'users/' : 'classes/' + className + '/' ) + object.objectId }; }); } From f20fe9c5071d59e7e547fb9dbb4e124071988425 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Thu, 23 Apr 2015 13:03:24 +0200 Subject: [PATCH 12/15] Changes and adds new tests Parse.test.js runs tests against the master key, while testRestApiKey.js runs tests against the rest api key to test sesstion tokens for users. --- lib/Parse.js | 6 +- test/Parse.test.js | 316 +++++++++++++++++++++++++++++------------ test/testRestApiKey.js | 78 ++++++++++ 3 files changed, 308 insertions(+), 92 deletions(-) create mode 100644 test/testRestApiKey.js diff --git a/lib/Parse.js b/lib/Parse.js index fc72423..29c8cb1 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -168,8 +168,8 @@ Parse.prototype = { }, // remove an object from the class store - deleteUser: function (objectId, callback) { - parseRequest.call(this, 'DELETE', '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/1/users/' + objectId, null, callback); + deleteUser: function (objectId, sessionToken, callback) { + parseRequest.call(this, 'DELETE', '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/1/users/' + objectId, null, callback, null, sessionToken); }, deleteAll: function(className, callback){ @@ -379,7 +379,7 @@ function parseRequest(method, path, data, callback, contentType, sessionToken) { var data; try { data = JSON.parse(json); - if ( data.code ) { + if ( data.code || data.error ) { throw (data); } callback(null, data); diff --git a/test/Parse.test.js b/test/Parse.test.js index e9c8ee1..e7414ed 100644 --- a/test/Parse.test.js +++ b/test/Parse.test.js @@ -1,3 +1,4 @@ +// this file runs tests against the master key var Parse = require('../index').Parse; // use environment variables APPLICATION_ID and MASTER_KEY to test against @@ -16,126 +17,263 @@ if (!application_id || !master_key) { var parse = new Parse(application_id, master_key); var className = 'NodeParseApiTest'; var className2 = 'NodeParseApiRelationTest'; -var object = { foo: Math.floor(Math.random() * 10000) }; // ERROR: if you change the type -var object2 = { foo: Math.floor(Math.random() * 10000) }; // ERROR: if you change the type -var object3 = { foo: Math.floor(Math.random() * 10000) }; // ERROR: if you change the type -var object4 = { foo: Math.floor(Math.random() * 10000) }; // ERROR: if you change the type -var stub; +var stub1; var stub2; +var stub3; +var stubRelation; -exports.insert = function (assert) { - parse.insert(className, object, function (err, response) { - err && console.log(err); - assert.ok(response); - stub = response; - assert.done(); +exports.insert = function (test) { + var data = { + foo: 'bar0', + baz: 'qux0', + quux: 'quuux' + }; + parse.insert(className, data, function (error, response) { + test.expect(1); + test.ok(!error, 'There shoudn\'t be an error object.'); + stub1 = response; + test.done(); }); - - }; -exports['insert 2'] = function(assert){ - parse.insert(className2,object2, function(err,response){ - err && console.log(err); - assert.ok(response); - stub2 = response; - assert.done(); - }); -} - - -exports.find = function (assert) { - parse.find(className, stub.objectId, function (err, response) { - assert.equal(object.foo, response.foo); - assert.done(); +exports.batchInsert = function (test) { + var batchRequests = [ + { + method: 'POST', + path: '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/1/classes/' + className, + body: { + foo: 'bar1', + baz: 'qux1', + quux: 'quuux' + } + }, + { + method: 'POST', + path: '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/1/classes/' + className, + body: { + foo: 'bar2', + baz: 'qux2', + quux: 'quuux' + } + } + ]; + parse.batch(batchRequests, function (error, response) { + test.expect(1); + test.ok(!error, 'There shoudn\'t be an error object.'); + stub2 = response[0].success; + stub3 = response[1].success; + test.done(); }); }; -exports['find with limit and order'] = function (assert) { - parse.findMany(className,{},'-createdAt',1, function (err1,res1){ - assert.equal(1, res1.results.length); - assert.equal(stub.objectId, res1.results[0].objectId); - assert.equal(stub.createdAt, res1.results[0].createdAt); - assert.done(); +exports.find = function (test) { + parse.find(className, stub1.objectId, function (err, response) { + test.equal(stub1.objectId, response.objectId); + test.done(); }); -} +}; -exports['find many'] = function (assert) { - parse.find(className, stub, function (err, response) { - assert.equal(1, response.results.length); - assert.equal(stub.objectId, response.results[0].objectId); - assert.equal(stub.createdAt, response.results[0].createdAt); - assert.equal(object.foo, response.results[0].foo); - assert.done(); +exports.findManyNoConstraints = function (test) { + parse.find(className, '', function (error, response) { + test.expect(3); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response.results.length === 3, 'There should be 3 objects in response.results.'); + test.equal(stub1.objectId, response.results[0].objectId, 'The first object should have the same objectId as the stub object.'); + test.done(); }); }; +// order limit skip keys include +exports.findManyWithConstraints = { + order: function (test) { + var query = { + order: '-foo' + }; + parse.find(className, query, function (error, response) { + test.expect(4); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.equal('bar0', response.results[2].foo, 'response.results[2].foo should be "bar0".'); + test.equal('bar1', response.results[1].foo, 'response.results[1].foo should be "bar1".'); + test.equal('bar2', response.results[0].foo, 'response.results[0].foo should be "bar2".'); + test.done(); + }); + }, + 'order keys skip': function (test) { + var query = { + order: 'foo', + keys: 'baz', + skip: 2 + }; + parse.find(className, query, function (error, response) { + test.ok(!error, 'There shoudn\'t be an error object.'); + test.equal('qux2', response.results[0].baz, 'response.results[0].baz should be "qux2".'); + test.done(); + }); + }, + 'order limit': function (test) { + var query = { + order: '-foo', + limit: 2 + }; + parse.find(className, query, function (error, response) { + test.expect(4); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response.results.length === 2, 'There should be 2 objects in response.results.'); + test.equal('bar1', response.results[1].foo, 'response.results[1].foo should be "bar1".'); + test.equal('qux1', response.results[1].baz, 'response.results[1].baz should be "qux1".'); + test.done(); + }); + } +}; +exports.deprecatedFindMany = { + setUp: function (callback) { + this.query = { + quux: 'quuux' + }; + callback(); + }, + '3 arguments': function (test) { + parse.findMany(className, this.query, function (error, response) { + test.expect(2); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response.results.length === 3, 'There should be 3 objects in response.results.'); + test.done(); + }); + }, + '5 arguments': function (test) { + parse.findMany(className, this.query, 'foo', 2, function (error, response) { + test.expect(3); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response.results.length === 2, 'There should be 2 objects in response.results.'); + test.equal('bar0', response.results[0].foo, 'response.results[0].foo should be "bar0".'); + test.done(); + }); + }, + '6 arguments': function (test) { + parse.findMany(className, this.query, 'foo', 2, 1, function (error, response) { + test.expect(3); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response.results.length === 2, 'There should be 2 objects in response.results.'); + test.equal('bar1', response.results[0].foo, 'response.results[0].foo should be "bar1".'); + test.done(); + }); + }, + 'invalid number of arguments': function (test) { + test.expect(1); + test.throws(function () {parse.findMany('foo', 'bar', 'baz', 'qux');}); + test.done(); + } +}; - -exports.update = function (assert) { - do { - var num = Math.floor(Math.random() * 10000); - } while (num == object.foo); - object.foo = num; - - parse.update(className, stub.objectId, object, function (err, response) { - err && console.log(err); - assert.ok(response); - exports.find(assert); // retest find on the updated object +exports.update = function (test) { + stub1.foo = 'bar00'; + parse.update(className, stub1.objectId, {foo: 'bar00'}, function (error, response) { + test.expect(4); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response); + parse.find(className, stub1.objectId, function (error, response) { + test.ok(!error, 'There shoudn\'t be an error object.'); + test.equal(stub1.foo, response.foo, 'response.foo should be "bar00".'); + test.done(); + }); }); }; +exports.insertClass2 = function (test) { + parse.insert(className2, {foo: 'bar'}, function (error, response) { + test.expect(1); + test.ok(!error, 'There shoudn\'t be an error object.'); + stubRelation = response; + test.done(); + }); +}; -exports['add relation'] = function (assert) { - parse.addRelation("secondObject",className,stub.objectId,className2,stub2.objectId, function (err ,response){ - err && console.log(response); - assert.ok(response); - assert.done(); - }); -} +exports.addRelation = function (test) { + parse.addRelation("secondObject", className2, stubRelation.objectId, className, stub1.objectId, function (error, response) { + test.expect(3); + test.ok(!error, 'There shoudn\'t be an error object.'); -exports['batch'] = function (assert) { - requests = [{"method":"PUT","path": "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/1/classes/"+className+'/'+stub.objectId, "body": object3},{"method":"PUT","path": "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/1/classes/"+className2+'/'+stub2.objectId, "body": object4} ]; - parse.batch(requests, function(err,response){ - err && console.log(response); - assert.ok(response); - assert.done(); + var query = { + where: { + $relatedTo: { + object: { + __type: 'Pointer', + className: className2, + objectId: stubRelation.objectId + }, + key: 'secondObject' + } + } + }; + parse.find(className, query, function (error, response) { + console.log(response); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.equal(stub1.foo, response.results[0].foo, 'The response object should contain the related object.'); + test.done(); + }); }); -} +}; -exports['delete'] = function (assert) { - parse['delete'](className, stub.objectId, function (err) { - err && console.log(err); - assert.ok(!err); - parse.find(className, stub.objectId, function (err, response) { - assert.equal(404, err.type); - assert.done(); +exports.deleteOne = function (test) { + parse.delete(className2, stubRelation.objectId, function (error, response) { + test.expect(3); + test.ok(!error, 'There shouldn\'t be an error object.'); + parse.find(className2, stubRelation.objectId, function (error, response) { + test.ok(error, 'There should be an error object.'); + test.equal(101, error.code, 'error.code should be 101.'); + test.done(); }); }); }; -exports['delete all'] = function(assert){ - parse.insert(className2,object2, function(err,response){ - parse.deleteAll(className2, function(){ - parse.findMany(className2, '', function(err, response){ - assert.equal(0, response.results.length); - assert.done(); - }); - }); +exports.deleteAll = function (test) { + parse.deleteAll(className, function (error, response) { + test.expect(2); + test.ok(!error, 'There shoudn\'t be an error object.'); + test.ok(response[0].hasOwnProperty('success')); + test.done(); }); -} +}; -exports['push notification error'] = function (assert) { +exports.userTests = { + insertUser : function (test) { + test.expect(1); + parse.insertUser({username: 'foo', password: 'bar'}, function (error, response) { + test.ok(!error, 'There shoudn\'t be an error object.'); + test.done(); + }); + }, + getUser: function (test) { + test.expect(2); + parse.getUser({where:{username: 'foo'}}, function (error, response) { + test.ok(!error, 'There shoudn\'t be an error object.'); + test.equal('foo', response.results[0].username, 'response.results[0].username should be foo.'); + test.done(); + }); + }, + deleteUser: function (test) { + test.expect(1); + parse.getUser({where:{username: 'foo'}}, function (error, response) { + parse.deleteUser(response.results[0].objectId, function (error, response) { + test.ok(!error, 'There shoudn\'t be an error object.'); + test.done(); + }); + }); + } +}; + +exports.pushNotificationError = function (test) { parse.sendPush({ channels: ['foobar'], data2: { alert: 'test message' } - }, function (error, result) { - assert.ok(error); - assert.equal(result, null); - assert.equal(error.message, 'Missing the push data. (Code: 115)'); - assert.done(); + }, function (error, response) { + test.expect(3); + test.ok(error); + test.equal(response, null); + test.equal(error.code, 115, 'error.code should be 115.'); + test.done(); }); -} +}; diff --git a/test/testRestApiKey.js b/test/testRestApiKey.js new file mode 100644 index 0000000..01d95da --- /dev/null +++ b/test/testRestApiKey.js @@ -0,0 +1,78 @@ +// this file runs tests against the rest api key +var Parse = require('../index').Parse; + +// use environment variables APPLICATION_ID and MASTER_KEY to test against +var application_id = process.env.APPLICATION_ID; +var rest_api_key = process.env.REST_API_KEY; + +// require the environment variables, or exit with explanation +if (!application_id || !rest_api_key) { + console.log('Set the following environment variables for the test Parse app'); + console.log(' export APPLICATION_ID=...'); + console.log(' export REST_API_KEY=...'); + process.exit(1); +} + +// global objects to test against +var parse = new Parse({app_id: application_id, api_key: rest_api_key}); +var user = {username: 'foo', password: 'bar'}; +var user2 = {username: 'baz', password: 'qux'}; +var userObject; +var user2Object; + +exports.userLogin = function (test) { + test.expect(4); + parse.insertUser(user2, function (error, response) { + test.ok(!error, 'Failed creating user.'); + user2Object = response; + parse.insertUser(user, function (error, response) { + test.ok(!error, 'Failed creating user.'); + userObject = response; + parse.loginUser(user.username, user.password, function (error, response) { + test.ok(!error, 'Login failed.'); + test.equal(user.username, response.username, 'Should be the same username.'); + test.done(); + }); + }); + }); +}; + +exports.editUser = function (test) { + test.expect(3); + parse.updateUser(userObject.objectId, {username: 'foo0'}, userObject.sessionToken, function (error, response) { + userObject.username = 'foo0'; + test.ok(!error); + parse.getUser({objectId: userObject.objectId}, function (error, response) { + test.ok(!error); + test.equal(userObject.username, response.username, 'usernames should be the same.'); + test.done(); + }); + }); +}; + +exports.editUserFail = function (test) { + test.expect(1); + parse.updateUser(user2Object.objectId, {username: 'baz0'}, userObject.sessionToken, function (error, response) { + test.ok(error); + test.done(); + }); +}; + +exports.me = function (test) { + test.expect(1); + parse.me(userObject.sessionToken, function (error, response) { + test.ok(!error); + test.done(); + }); +}; + +exports.deleteUser = function (test) { + test.expect(2); + parse.deleteUser(userObject.objectId, userObject.sessionToken, function (error, response) { + test.ok(!error); + parse.deleteUser(user2Object.objectId, user2Object.sessionToken, function (error, response) { + test.ok(!error); + test.done(); + }); + }); +}; From 237a17946089d88c750ea5eb812c0414bcf1cbf5 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Thu, 23 Apr 2015 15:36:10 +0200 Subject: [PATCH 13/15] Changes getUser to findUser for consistency with find getUser and getFileByUser now redirect to their respective newer version while logging a warning message to the console. Also removes one console.log from Parse.test.js and adds one more contributor. --- lib/Parse.js | 53 +++++++++++++++++++++++++++++++++++----------- package.json | 3 ++- test/Parse.test.js | 1 - 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/lib/Parse.js b/lib/Parse.js index 29c8cb1..125d002 100644 --- a/lib/Parse.js +++ b/lib/Parse.js @@ -103,23 +103,37 @@ Parse.prototype = { }, // retrieve contents of one or more user objects - getUser: function (query, callback, deprecatedCallback) { - if ( arguments.length === 3 ) { - console.warn('Logging in with "getUser" is deprecated, use loginUser instead.'); - console.warn('Use "getUser" to retrieve one or more user object contents.'); - this.loginUser(query, callback, deprecatedCallback); + findUser: function (query, callback) { + if ( arguments.length !== 2 ) { + throw new Error('Unexpected number of arguments.'); } else { this.find('_User', query, callback); } }, // get an object belonging to a certain User - getFileByUser: function(userId, className, callback) { + findFileByUser: function(userId, className, callback) { queryString = 'where={"user":' + '"' + userId + '"' + '}'; encodedString = encodeURIComponent(queryString); parseRequest.call(this, 'GET', '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/1/classes/' + className + '?' + encodedString, null, callback); }, + getUser: function (query, callback, deprecatedCallback) { + console.warn('getUser is deprecated, user findUser instead.'); + if ( arguments.length === 3 ) { + console.warn('Logging in with "getUser" is deprecated, use loginUser instead.'); + console.warn('Use "findUser" to retrieve one or more user object contents.'); + this.loginUser(query, callback, deprecatedCallback); + } else { + this.findUser(query, callback); + } + }, + + getFileByUser: function(userId, className, callback) { + console.warn('getFileByUser is deprecated, user findFileByUser instead.'); + this.findFileByUser(userId, className, callback); + }, + // insert an object into Parse insertCustom: function (className, object, callback) { parseRequest.call(this, 'POST', '/1/' + className, object, callback); @@ -132,8 +146,11 @@ Parse.prototype = { // update a User object's email address updateUserEmail: function(objectId, data, sessionToken, callback) { - if ( arguments.length !== 4 ) { - throw new Error('Unexpected number of arguments.'); + switch ( arguments.length ) { + case 3: callback = sessionToken; + break; + case 4: break; + default: throw new Error('Unexpected number of arguments.'); } data = { email: data }; parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback, null, sessionToken); @@ -141,8 +158,11 @@ Parse.prototype = { // update a User object's username* updateUserName: function(objectId, data, sessionToken, callback) { - if ( arguments.length !== 4 ) { - throw new Error('Unexpected number of arguments.'); + switch ( arguments.length ) { + case 3: callback = sessionToken; + break; + case 4: break; + default: throw new Error('Unexpected number of arguments.'); } data = { username: data }; parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback, null, sessionToken); @@ -150,8 +170,11 @@ Parse.prototype = { // update any keys of a User object updateUser: function (objectId, data, sessionToken, callback) { - if ( arguments.length !== 4 ) { - throw new Error('Unexpected number of arguments.'); + switch ( arguments.length ) { + case 3: callback = sessionToken; + break; + case 4: break; + default: throw new Error('Unexpected number of arguments.'); } parseRequest.call(this, 'PUT', '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/1/users/' + objectId, data, callback, null, sessionToken); }, @@ -169,6 +192,12 @@ Parse.prototype = { // remove an object from the class store deleteUser: function (objectId, sessionToken, callback) { + switch ( arguments.length ) { + case 2: callback = sessionToken; + break; + case 3: break; + default: throw new Error('Unexpected number of arguments'); + } parseRequest.call(this, 'DELETE', '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/1/users/' + objectId, null, callback, null, sessionToken); }, diff --git a/package.json b/package.json index 915e6d7..1dcfd03 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "Rafael Galdêncio", "Akhmad Fathonih", "Kody J. Peterson", - "Jo Jordens" + "Jo Jordens", + "Appsaloon" ], "main": "index", "scripts": { diff --git a/test/Parse.test.js b/test/Parse.test.js index e7414ed..342f61c 100644 --- a/test/Parse.test.js +++ b/test/Parse.test.js @@ -207,7 +207,6 @@ exports.addRelation = function (test) { } }; parse.find(className, query, function (error, response) { - console.log(response); test.ok(!error, 'There shoudn\'t be an error object.'); test.equal(stub1.foo, response.results[0].foo, 'The response object should contain the related object.'); test.done(); From 0b5bc54e1e4bb9fe36f354c051cadb55d24db5ee Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Thu, 23 Apr 2015 15:36:38 +0200 Subject: [PATCH 14/15] Updates readme.md --- readme.md | 622 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 437 insertions(+), 185 deletions(-) diff --git a/readme.md b/readme.md index d670d22..3c8db00 100644 --- a/readme.md +++ b/readme.md @@ -4,274 +4,526 @@ Node Parse API install ------- - npm install node-parse-api - +``` +npm install node-parse-api +``` + examples -------- -### setup with MASTER_KEY (old way) +### setup with MASTER_KEY - var Parse = require('node-parse-api').Parse; +```javascript +var Parse = require('node-parse-api').Parse; - var APP_ID = ...; - var MASTER_KEY = ...; +var APP_ID = ...; +var MASTER_KEY = ...; - var app = new Parse(APP_ID, MASTER_KEY); +var app = new Parse(APP_ID, MASTER_KEY); +``` -### setup with API_KEY (new way) +### setup with API_KEY - var Parse = require('node-parse-api').Parse; +```javascript +var Parse = require('node-parse-api').Parse; - var options = { - app_id:'...', - api_key:'...' // master_key:'...' could be used too - } +var options = { + app_id:'...', + api_key:'...' // master_key:'...' could be used too +} - var app = new Parse(options); +var app = new Parse(options); +``` ### insert an object - // add a Foo object, { foo: 'bar' } - app.insert('Foo', { foo: 'bar' }, function (err, response) { - console.log(response); - }); +* insert(className `string`, data `object`, callback `function`) + +```javascript +// add a Foo object, { foo: 'bar' } +app.insert('Foo', { foo: 'bar' }, function (err, response) { + console.log(response); +}); +``` ### insert a User - app.insertCustom('users', { - username: 'tom@j.com', - password: 'wow' - }, function (err, response) { - console.log(response); - }); +* insertUser(data `object`, callback `function`) + +```javascript +app.insertUser({ + username: 'foo', + password: 'bar' +}, function (err, response) { + console.log(response); +}); +``` + +More properties can be provided, but username and password are required. + +### insert a User with a Pointer + +```javascript +app.insertUser({ + username: 'foo', + password: 'bar', + pointer/*can have any name*/: { + __type: 'Pointer', + className: , + objectId: + } + }, function (err, response) { + console.log(response); +}); +``` ### insert a User with GeoPoints - app.insertCustom('users', { foo: 'bar', location: {__type: 'GeoPoint', latitude: , longitude: } }, function (err, response) { - console.log(response); - }); +```javascript +app.insertUser({ + username: 'foo', + password: 'bar', + location: { + __type: 'GeoPoint', + latitude: , + longitude: + } + }, function (err, response) { + console.log(response); +}); +``` + +### user login + +loginUser(username `string`, password `string`, callback `function`) + +Response contains all of the user fields except password, also includes a sessionToken for this user. + +```javascript +app.loginUser('foo', 'bar', function (error, response) { + // response = {sessionToken: '', createdAt: '', ... } + }); +``` + +### me + +me(sessionToken `string`, callback `function`) + +```javascript +app.me('sessionToken', function (error, response) { + // response is same as getUser response +}); +``` ### insert a file - app.insertFile(fileName, data, fileType, function (err, response) { - fileLink = response.url; - parseName = response.name; - app.insert('Foo', { "foo" : fileLink, "bar" : parseName }, function(erro, res){ - }) - }); +Method parameters: insertFile(fileName `string`, data `string/buffer`, contentType `string`, callback `function`) + +```javascript +// first upload the file to the parse cloud +app.insertFile('foo.txt', 'bar', 'text/plain', function (err, response) { + // then insert a new object with the link to the new file + app.insert('MyFile', {__type: 'File', "name": response.name }, function (error, response) { + }); +}); +``` ### find one - // the Foo with id = 'someId' - app.find('Foo', 'someId', function (err, response) { - console.log(response); - }); +find(className `string`, query `object`, callback `function`) -### find many +```javascript +// the Foo with id = 'someId' +app.find('Foo', {objectId: 'someId'}, function (err, response) { + console.log(response); +}); +``` - // all Foo objects with foo = 'bar' - app.findMany('Foo', { foo: 'bar' }, function (err, response) { - console.log(response); - }); +Returned fields can be restricted with the 'keys' query. +```javascript +var query = { + objectId: 'someId', + keys: 'foo,bar' +}; +app.find('Foo', query, function (error, response) { + //response object will only contain foo and bar fields, as well as the special built-in fields (objectId, createdAt and updatedAt) + }); +``` - // all Foo objects - app.findMany('Foo', '', function (err, response) { - console.log(response); - }): +### find many + +find(className `string`, query `object`, callback `function`) + +```javascript +// all Foo objects with foo = 'bar' +app.find('Foo', {where: {foo: 'bar'}}, function (err, response) { + console.log(response); +}); + +// all Foo objects +// '', null, undefined or any other falsy value will work +app.find('Foo', '', function (err, response) { + console.log(response); +}): +``` + +All types of query constraints Parse provides can be added to the query object as properties. (order, limit, keys, count, include...) + +```javascript +var query = { + where: { + foo: 'bar', + baz: 'qux' + }, + limit: 10, + skip: 5, + order: '-createdAt' +}; +app.find('Foo', query, function (error, response ) { + // the first 5 results will be ignored and the next 10 results will be returned + // response.results will contain up to 10 objects with foo = 'bar' and baz = 'qux', sorted from latest to oldest + }); +``` + +### find one user + +getUser(query `object`, callback `function`) + +```javascript +app.find({objectId: 'someId'}, function (err, response) { + console.log(response); +}); +``` + +### find many users + +getUser(query `object`, callback `function`) + +```javascript +// all users with foo = 'bar' +app.find({where: {foo: 'bar'}}, function (err, response) { + console.log(response); +}); + +// all users +// '', null, undefined or any other falsy value will work +app.find('', function (err, response) { + console.log(response); +}): +``` ### count the number of objects - // just use findMany, and call results.length on the response - app.findMany('Foo', { user: '' }, function (err, response) { - console.log(response.results.length); - }); +```javascript + +var query = { + count: 1, + limit: 0 +}; +app.find('Foo', query, function (error, response) { + // { + // results: [], + // count: 123 + // } +}); +``` + +### edit an object + +update(className `string`, objectId `string`, callback `function`) + +```javascript +app.update('Foo', 'someId', {foo: 'bar'}, function (err, response) { + console.log(response); +}); +``` + +### delete an object + +delete(className `string`, objectId `string`, callback `function`) + +```javascript +app.delete('Foo', 'someId', function (err, response) { + // response = {} +}); +``` + +### delete all objects in a class + +deleteAll(className `string`, callback `function`) + +```javascript +app.deleteAll('Foo', function (err, response) { + // response = [{success: {}, success: {}, ... }] +}); +``` + +### delete user -### update +deleteUser(objectId `string`, [sessionToken `string`], callback `function`) - app.update('Foo', 'someId', { foo: 'fubar' }, function (err, response) { - console.log(response); - }); +If you are using the master key you don't need any session tokens. -### delete +```javascript +app.deleteUser('someId', function (err, response) { + // response = {} +}); +``` - app.delete('Foo', 'someId', function (err) { - // nothing to see here - }); +If you're using the rest api key you will need a session token and will only be able to delete the user object of the matching user. -### deleteAll +```javascript +app.deleteUser('someId', 'sessionToken', function (error, response) { + // response = {} +}); +``` - app.deleteAll('Foo', function (err) { - // nothing to see here - }); +### delete all users + +deleteAll(callback `function`) + +This will only work when using the master key. + +```javascript +app.deleteAllUsers(function (err, response) { + // response = [{success: {}, success: {}, ... }] +}); +``` ### reset a password - //email is built into Parse's special User class - app.passwordReset(email, function(err, response){ - console.log(response); - }); +passwordReset(data `string`, callback `function`) -### update User email +```javascript +//email is built into Parse's special User class +app.passwordReset(email, function(err, response){ + console.log(response); +}); +``` - //email is built into Parse's special User class - app.updateUserEmail(objectId, email, function(err, response){ - if (err) { - console.log(err); - } else { - console.log(response); - } - }); +### edit a user object + +updateUser(objectId `string`, data `object`, [sessionToken `string`], callback `function`) + +With master key + +```javascript +app.updateUser('someId', {email: 'foo@example.com'}, function(err, response){ + console.log(response); +}); +``` + +or with rest api key + +```javascript +app.updateUser('someId', {email: 'foo@example.com'}, 'sesstionToken', function(err, response){ + console.log(response); +}); +``` + +### batch requests + +batch(requests `array`, callback `function`) + +```javascript +var requests = [ + { + method: 'POST', + path: '/1/classes/Foo', + body: { + foo: 'bar1', + baz: 'qux1' + } + }, + { + method: 'POST', + path: '/1/classes/Foo', + body: { + foo: 'bar2', + baz: 'qux2' + } + } +]; +app.batch(requests, function (error, response) { + // response = [{success: {createdAt: '', objectId: ''}, {success: {...}}}] +}); +``` ### insert installation data - //first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. - app.insertInstallationData("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", function(err, response){ - if (err) { - console.log(err); - } else { - console.log(response); - } - }); +```javascript +//first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. +app.insertInstallationData("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", function(err, response){ + if (err) { + console.log(err); + } else { + console.log(response); + } +}); +``` ### insert installation data with timeZone - //first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. Third arg is the timezone string. - app.insertInstallationDataWithTimeZone("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "EST", function(err, response){ - if (err) { - console.log(err); - } else { - console.log(response); - } - }); +```javascript +//first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. Third arg is the timezone string. +app.insertInstallationDataWithTimeZone("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "EST", function(err, response){ + if (err) { + console.log(err); + } else { + console.log(response); + } +}); +``` ### insert installation data with channels - //first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. Third arg is the channels array. - arr = ["news", "sports"]; - app.insertInstallationDataWithChannels("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", arr, function(err, response){ - if (err) { - console.log(err); - } else { - console.log(response); - } - }); +```javascript +//first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. Third arg is the channels array. +arr = ["news", "sports"]; +app.insertInstallationDataWithChannels("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", arr, function(err, response){ + if (err) { + console.log(err); + } else { + console.log(response); + } +}); +``` ### insert installation data with timeZone and channels - //first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. Third arg is the timezone string. 4th is the channels array. - arr = ["news", "sports"]; - app.insertInstallationDataWithTimeZoneAndChannels("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "EST", arr, function(err, response){ - if (err) { - console.log(err); - } else { - console.log(response); - } - }); +```javascript +//first arg is either 'ios' or 'android'. second arg is either the Apple deviceToken or the Android installationId. Third arg is the timezone string. 4th is the channels array. +arr = ["news", "sports"]; +app.insertInstallationDataWithTimeZoneAndChannels("ios", "0123456784abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "EST", arr, function(err, response){ + if (err) { + console.log(err); + } else { + console.log(response); + } +}); +``` ### create a role for a particular user - //create a data object that links the user object's objectId to the role - - var data = { - name: 'Administrator', - ACL: { - "*": { - "read": true - } - }, - roles: { - "__op": "AddRelation", - "objects": [ - { - "__type": "Pointer", - "className": "_Role", - "objectId": "" - } - ] - }, - users: { - "__op": "AddRelation", - "objects": [ - { - "__type": "Pointer", - "className": "_User", - "objectId": "" - } - ] +```javascript +//create a data object that links the user object's objectId to the role + +var data = { + name: 'Administrator', + ACL: { + "*": { + "read": true + } + }, + roles: { + "__op": "AddRelation", + "objects": [ + { + "__type": "Pointer", + "className": "_Role", + "objectId": "" } - }; + ] + }, + users: { + "__op": "AddRelation", + "objects": [ + { + "__type": "Pointer", + "className": "_User", + "objectId": "" + } + ] + } +}; - app.insertRole(data, function(err, resp){ - console.log(resp); - }); + app.insertRole(data, function(err, resp){ + console.log(resp); + }); +``` ### get a role - //pass the role object's objectId - app.getRole("", function(err, resp){ - console.log(resp); - }); +```javascript +//pass the role object's objectId +app.getRole("", function(err, resp){ + console.log(resp); +}); +``` ### update a role - //pass the objectId of the role, data contains the user's objectId - - var data = { - users: { - "__op": "RemoveRelation", - "objects": [ - { - "__type": "Pointer", - "className": "_User", - "objectId": "" - } - ] + +```javascript +//pass the objectId of the role, data contains the user's objectId + +var data = { + users: { + "__op": "RemoveRelation", + "objects": [ + { + "__type": "Pointer", + "className": "_User", + "objectId": "" } - }; + ] + } +}; - app.updateRole("", data, function(err, resp){ - console.log(resp); - }); + app.updateRole("", data, function(err, resp){ + console.log(resp); + }); +``` ### delete a role - //pass the objectId of the role - app.deleteRole("", function(err, resp){}); +```javascript +//pass the objectId of the role +app.deleteRole("", function(err, resp){}); +``` ### get all the roles - app.getRoles(function(err, resp){}); +```javascript +app.getRoles(function(err, resp){}); +``` ### get a role against a cetain param - var params = { - where: { name: "Administrator" } - }; +```javascript +var params = { + where: { name: "Administrator" } +}; - app.getRoles(params, function(err, resp){ - console.log(resp); - }); + app.getRoles(params, function(err, resp){ + console.log(resp); + }); +``` ### send a push notification - //The data param has to follow the data structure as described in the [Parse REST API](https://www.parse.com/docs/rest#push) - var notification = { - channels: [''], - data: { - alert: "sending too many push notifications is obnoxious" - } - }; - app.sendPush(notification, function(err, resp){ - console.log(resp); - }); +```javascript +//The data param has to follow the data structure as described in the [Parse REST API](https://www.parse.com/docs/rest#push) +var notification = { + channels: [''], + data: { + alert: "sending too many push notifications is obnoxious" + } +}; +app.sendPush(notification, function(err, resp){ + console.log(resp); +}); +``` ### note on sending dates - //when inserting a data, you must use the Parse date object structure, i.e.: - { - "__type": "Date", - "iso": new Date("", "", "").toJSON() - } +```javascript +//when inserting a data, you must use the Parse date object structure, i.e.: +{ + "__type": "Date", + "iso": new Date("", "", "").toJSON() +} +``` # License From 1f16e824992cbe727ae92c3012b5b9499131eae0 Mon Sep 17 00:00:00 2001 From: Jo Jordens Date: Thu, 23 Apr 2015 16:02:51 +0200 Subject: [PATCH 15/15] Corrects some mistakes in readme.md --- readme.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/readme.md b/readme.md index 3c8db00..df2d79f 100644 --- a/readme.md +++ b/readme.md @@ -95,7 +95,7 @@ app.insertUser({ ### user login -loginUser(username `string`, password `string`, callback `function`) +* loginUser(username `string`, password `string`, callback `function`) Response contains all of the user fields except password, also includes a sessionToken for this user. @@ -107,7 +107,7 @@ app.loginUser('foo', 'bar', function (error, response) { ### me -me(sessionToken `string`, callback `function`) +* me(sessionToken `string`, callback `function`) ```javascript app.me('sessionToken', function (error, response) { @@ -117,7 +117,7 @@ app.me('sessionToken', function (error, response) { ### insert a file -Method parameters: insertFile(fileName `string`, data `string/buffer`, contentType `string`, callback `function`) +* insertFile(fileName `string`, data `string/buffer`, contentType `string`, callback `function`) ```javascript // first upload the file to the parse cloud @@ -130,7 +130,7 @@ app.insertFile('foo.txt', 'bar', 'text/plain', function (err, response) { ### find one -find(className `string`, query `object`, callback `function`) +* find(className `string`, query `object`, callback `function`) ```javascript // the Foo with id = 'someId' @@ -153,7 +153,7 @@ app.find('Foo', query, function (error, response) { ### find many -find(className `string`, query `object`, callback `function`) +* find(className `string`, query `object`, callback `function`) ```javascript // all Foo objects with foo = 'bar' @@ -188,7 +188,7 @@ app.find('Foo', query, function (error, response ) { ### find one user -getUser(query `object`, callback `function`) +* getUser(query `object`, callback `function`) ```javascript app.find({objectId: 'someId'}, function (err, response) { @@ -198,7 +198,7 @@ app.find({objectId: 'someId'}, function (err, response) { ### find many users -getUser(query `object`, callback `function`) +* getUser(query `object`, callback `function`) ```javascript // all users with foo = 'bar' @@ -231,7 +231,7 @@ app.find('Foo', query, function (error, response) { ### edit an object -update(className `string`, objectId `string`, callback `function`) +* update(className `string`, objectId `string`, callback `function`) ```javascript app.update('Foo', 'someId', {foo: 'bar'}, function (err, response) { @@ -241,7 +241,7 @@ app.update('Foo', 'someId', {foo: 'bar'}, function (err, response) { ### delete an object -delete(className `string`, objectId `string`, callback `function`) +* delete(className `string`, objectId `string`, callback `function`) ```javascript app.delete('Foo', 'someId', function (err, response) { @@ -251,7 +251,7 @@ app.delete('Foo', 'someId', function (err, response) { ### delete all objects in a class -deleteAll(className `string`, callback `function`) +* deleteAll(className `string`, callback `function`) ```javascript app.deleteAll('Foo', function (err, response) { @@ -261,7 +261,7 @@ app.deleteAll('Foo', function (err, response) { ### delete user -deleteUser(objectId `string`, [sessionToken `string`], callback `function`) +* deleteUser(objectId `string`, [sessionToken `string`], callback `function`) If you are using the master key you don't need any session tokens. @@ -281,7 +281,7 @@ app.deleteUser('someId', 'sessionToken', function (error, response) { ### delete all users -deleteAll(callback `function`) +* deleteAllUsers(callback `function`) This will only work when using the master key. @@ -293,7 +293,7 @@ app.deleteAllUsers(function (err, response) { ### reset a password -passwordReset(data `string`, callback `function`) +* passwordReset(data `string`, callback `function`) ```javascript //email is built into Parse's special User class @@ -304,7 +304,7 @@ app.passwordReset(email, function(err, response){ ### edit a user object -updateUser(objectId `string`, data `object`, [sessionToken `string`], callback `function`) +* updateUser(objectId `string`, data `object`, [sessionToken `string`], callback `function`) With master key @@ -324,7 +324,7 @@ app.updateUser('someId', {email: 'foo@example.com'}, 'sesstionToken', function(e ### batch requests -batch(requests `array`, callback `function`) +* batch(requests `array`, callback `function`) ```javascript var requests = [ @@ -535,4 +535,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.