From f259a3b17e10b39bec3b6f8c1f5c2a4ca433d87d Mon Sep 17 00:00:00 2001 From: Florent Vilmart Date: Tue, 29 Mar 2016 09:44:04 -0400 Subject: [PATCH 1/2] Supports increment as well as Increment --- spec/Parse.Push.spec.js | 94 ++++++++++++++++++++----------- src/Controllers/PushController.js | 4 +- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/spec/Parse.Push.spec.js b/spec/Parse.Push.spec.js index 7dc02d43c8..5507b0f300 100644 --- a/spec/Parse.Push.spec.js +++ b/spec/Parse.Push.spec.js @@ -1,28 +1,32 @@ 'use strict'; + + describe('Parse.Push', () => { - it('should properly send push', (done) => { - var pushAdapter = { - send: function(body, installations) { - var badge = body.data.badge; - let promises = installations.map((installation) => { - if (installation.deviceType == "ios") { - expect(installation.badge).toEqual(badge); - expect(installation.originalBadge+1).toEqual(installation.badge); - } else { - expect(installation.badge).toBeUndefined(); - } - return Promise.resolve({ - err: null, - deviceType: installation.deviceType, - result: true - }) - }); - return Promise.all(promises) - }, - getValidPushTypes: function() { - return ["ios", "android"]; - } + + var setup = function() { + var pushAdapter = { + send: function(body, installations) { + var badge = body.data.badge; + let promises = installations.map((installation) => { + if (installation.deviceType == "ios") { + expect(installation.badge).toEqual(badge); + expect(installation.originalBadge+1).toEqual(installation.badge); + } else { + expect(installation.badge).toBeUndefined(); + } + return Promise.resolve({ + err: null, + deviceType: installation.deviceType, + result: true + }) + }); + return Promise.all(promises); + }, + getValidPushTypes: function() { + return ["ios", "android"]; } + } + setServerConfiguration({ appId: Parse.applicationId, masterKey: Parse.masterKey, @@ -31,6 +35,7 @@ describe('Parse.Push', () => { adapter: pushAdapter } }); + var installations = []; while(installations.length != 10) { var installation = new Parse.Object("_Installation"); @@ -41,21 +46,46 @@ describe('Parse.Push', () => { installation.set("deviceType", "ios"); installations.push(installation); } - Parse.Object.saveAll(installations).then(() => { + return Parse.Object.saveAll(installations); + } + + it('should properly send push', (done) => { + return setup().then(() => { return Parse.Push.send({ - where: { - deviceType: 'ios' - }, - data: { - badge: 'Increment', - alert: 'Hello world!' - } - }, {useMasterKey: true}); + where: { + deviceType: 'ios' + }, + data: { + badge: 'Increment', + alert: 'Hello world!' + } + }, {useMasterKey: true}) }) .then(() => { done(); }, (err) => { - console.error(err); + console.error(); + fail('should not fail sending push') + done(); + }); + }); + + it('should properly send push with lowercaseIncrement', (done) => { + return setup().then(() => { + return Parse.Push.send({ + where: { + deviceType: 'ios' + }, + data: { + badge: 'increment', + alert: 'Hello world!' + } + }, {useMasterKey: true}) + }).then(() => { + done(); + }, (err) => { + console.error(); + fail('should not fail sending push') done(); }); }); diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index 4553783088..2272a708ad 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -56,7 +56,7 @@ export class PushController extends AdaptableController { if (body.data && body.data.badge) { let badge = body.data.badge; let op = {}; - if (badge == "Increment") { + if (typeof badge == 'string' && badge.toLowerCase() === 'increment') { op = { $inc: { badge: 1 } } } else if (Number(badge)) { op = { $set: { badge: badge } } @@ -97,7 +97,7 @@ export class PushController extends AdaptableController { } sendToAdapter(body, installations, pushStatus, config) { - if (body.data && body.data.badge && body.data.badge == "Increment") { + if (body.data && body.data.badge && typeof body.data.badge == 'string' && body.data.badge.toLowerCase() == "increment") { // Collect the badges to reduce the # of calls let badgeInstallationsMap = installations.reduce((map, installation) => { let badge = installation.badge; From 1b8e613dfb6f114878779e1012a33973fa273c2e Mon Sep 17 00:00:00 2001 From: yuzeh Date: Fri, 25 Mar 2016 16:11:27 -0700 Subject: [PATCH 2/2] Clean authData of null values on _User update Adds a step to the RestWrite#execute chain: it cleans the response authData object of null values. For example, this: {"authData": {"anonymous": null}, "updatedAt", ...} will be transformed to this: {"updatedAt", ...} And this: {"authData": {"anonymous": null, "twitter": ...}, "updatedAt", ...} will be transformed to this: {"authData": {"twitter": ...}, "updatedAt", ...} Fixing this issue will fix anonymous user upgrades from the Android SDK. --- spec/ParseUser.spec.js | 59 ++++++++++++++++++++++++++++++++++++++++++ src/RestWrite.js | 18 +++++++++++++ 2 files changed, 77 insertions(+) diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index ccfdb4b39e..941e1a0c55 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -2061,6 +2061,65 @@ describe('Parse.User testing', () => { }) }); + // https://github.com/ParsePlatform/parse-server/issues/1198 + it('should cleanup null authData keys ParseUser update', (done) => { + Parse.Cloud.beforeSave('_User', (req, res) => { + req.object.set('foo', 'bar'); + res.success(); + }); + + // Simulate anonymous user save + new Promise((resolve, reject) => { + request.post({ + url: 'http://localhost:8378/1/classes/_User', + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + }, + json: {authData: {anonymous: {id: '00000000-0000-0000-0000-000000000001'}}} + }, (err, res, body) => { + if (err) { + reject(err); + } else { + resolve(body); + } + }); + }).then((user) => { + // Simulate registration + return new Promise((resolve, reject) => { + request.put({ + url: 'http://localhost:8378/1/classes/_User/' + user.objectId, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Session-Token': user.sessionToken, + 'X-Parse-REST-API-Key': 'rest', + }, + json: { + authData: {anonymous: null}, + user: 'user', + password: 'password', + } + }, (err, res, body) => { + if (err) { + reject(err); + } else { + resolve(body); + } + }); + }); + }).then((user) => { + expect(typeof user).toEqual('object'); + expect(user.authData).toBeUndefined(); + Parse.Cloud._removeHook('Triggers', 'beforeSave', '_User'); + done(); + }).catch((err) => { + fail('no request should fail: ' + JSON.stringify(err)); + Parse.Cloud._removeHook('Triggers', 'beforeSave', '_User'); + done(); + }); + }); + + it('should aftersave with full object', (done) => { var hit = 0; Parse.Cloud.afterSave('_User', (req, res) => { diff --git a/src/RestWrite.js b/src/RestWrite.js index f00d852bc9..ba1bfdca1c 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -83,6 +83,8 @@ RestWrite.prototype.execute = function() { return this.handleFollowup(); }).then(() => { return this.runAfterTrigger(); + }).then(() => { + return this.cleanUserAuthData(); }).then(() => { return this.response; }); @@ -824,5 +826,21 @@ RestWrite.prototype.sanitizedData = function() { return Parse._decode(undefined, data); } +RestWrite.prototype.cleanUserAuthData = function() { + if (this.response && this.response.response && this.className === '_User') { + let user = this.response.response; + if (user.authData) { + Object.keys(user.authData).forEach((provider) => { + if (user.authData[provider] === null) { + delete user.authData[provider]; + } + }); + if (Object.keys(user.authData).length == 0) { + delete user.authData; + } + } + } +}; + export default RestWrite; module.exports = RestWrite;