diff --git a/spec/SNSPushAdapter.spec.js b/spec/SNSPushAdapter.spec.js index 50785af..d7d006c 100644 --- a/spec/SNSPushAdapter.spec.js +++ b/spec/SNSPushAdapter.spec.js @@ -61,7 +61,7 @@ describe('SNSPushAdapter', () => { it('can send push notifications', (done) => { // Mock SNS sender - var snsSender = jasmine.createSpyObj('sns', ['createPlatformEndpoint', 'publish']); + var snsSender = jasmine.createSpyObj('sns', ['createPlatformEndpoint', 'publish', 'setEndpointAttributes']); snsPushAdapter.sns = snsSender; // Mock android ios senders @@ -178,11 +178,16 @@ describe('SNSPushAdapter', () => { it('can send SNS Payload', (done) => { // Mock out Amazon SNS token exchange - var snsSender = jasmine.createSpyObj('sns', ['publish']) - snsSender.publish.and.callFake(function (object, callback) { + var snsSender = jasmine.createSpyObj('sns', ['publish', 'setEndpointAttributes']) + + snsSender.setEndpointAttributes.and.callFake(function (params, callback) { callback(null, '123'); }); - + + //snsSender.publish.and.callFake(function (object, callback) { + // callback(null, '123'); + //}); + snsPushAdapter.sns = snsSender; // Mock installations @@ -195,8 +200,10 @@ describe('SNSPushAdapter', () => { var callback = jasmine.createSpy(); promise.then(function (response) { - expect(snsSender.publish).toHaveBeenCalled(); - var args = snsSender.publish.calls.first().args; + expect(snsSender.setEndpointAttributes).toHaveBeenCalled(); + var args = snsSender.setEndpointAttributes.calls.first().args; + //expect(snsSender.publish).toHaveBeenCalled(); + //var args = snsSender.publish.calls.first().args; expect(args[0].MessageStructure).toEqual("json"); expect(args[0].TargetArn).toEqual("123"); expect(args[0].Message).toEqual('{"test":"hello"}'); @@ -207,7 +214,7 @@ describe('SNSPushAdapter', () => { it('errors exchanging ARNS', (done) => { // Mock out Amazon SNS token exchange - var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint']); + var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint', 'setEndpointAttributes']); snsSender.createPlatformEndpoint.and.callFake(function (object, callback) { callback("error", {}); @@ -221,10 +228,15 @@ describe('SNSPushAdapter', () => { it('errors sending SNS Payload to Android and iOS', (done) => { - var snsSender = jasmine.createSpyObj('sns', ['publish']) - snsSender.publish.and.callFake(function (object, callback) { - callback({'stack': 'abc'}, {}); + var snsSender = jasmine.createSpyObj('sns', ['publish', 'setEndpointAttributes']) + + snsSender.setEndpointAttributes.and.callFake(function (params, callback) { + callback(null, '123'); }); + + //snsSender.publish.and.callFake(function (object, callback) { + // callback({'stack': 'abc'}, {}); + //}); snsPushAdapter.sns = snsSender; @@ -238,7 +250,8 @@ describe('SNSPushAdapter', () => { var callback = jasmine.createSpy(); promise.catch(function (response) { - expect(snsSender.publish).toHaveBeenCalled(); + expect(snsSender.setEndpointAttributes).toHaveBeenCalled(); + //expect(snsSender.publish).toHaveBeenCalled(); expect(response.transmitted).toBeFalsy(); expect(response.response).toEqual('abc'); done(); @@ -247,15 +260,19 @@ describe('SNSPushAdapter', () => { it('can send SNS Payload to Android and iOS', (done) => { // Mock out Amazon SNS token exchange - var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint']); + var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint','setEndpointAttributes']); snsSender.createPlatformEndpoint.and.callFake(function (object, callback) { callback(null, {'EndpointArn': 'ARN'}); }); - snsSender.publish.and.callFake(function (object, callback) { + snsSender.setEndpointAttributes.and.callFake(function (params, callback) { callback(null, '123'); }); + + //snsSender.publish.and.callFake(function (object, callback) { + // callback(null, '123'); + //}); snsPushAdapter.sns = snsSender; @@ -274,22 +291,28 @@ describe('SNSPushAdapter', () => { var promise = snsPushAdapter.send({"test": "hello"}, installations); promise.then(function () { - expect(snsSender.publish).toHaveBeenCalled(); - expect(snsSender.publish.calls.count()).toEqual(2); + expect(snsSender.setEndpointAttributes).toHaveBeenCalled(); + expect(snsSender.setEndpointAttributes.calls.count()).toEqual(2); + //expect(snsSender.publish).toHaveBeenCalled(); + //expect(snsSender.publish.calls.count()).toEqual(2); done(); }); }); it('can send to APNS with known identifier', (done) => { - var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint']); + var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint','setEndpointAttributes']); snsSender.createPlatformEndpoint.and.callFake(function (object, callback) { callback(null, {'EndpointArn': 'ARN'}); }); - snsSender.publish.and.callFake(function (object, callback) { + snsSender.setEndpointAttributes.and.callFake(function (params, callback) { callback(null, '123'); }); + + //snsSender.publish.and.callFake(function (object, callback) { + // callback(null, '123'); + //}); snsPushAdapter.sns = snsSender; @@ -297,22 +320,27 @@ describe('SNSPushAdapter', () => { expect(promises.length).toEqual(1); Promise.all(promises).then(function () { - expect(snsSender.publish).toHaveBeenCalled(); + expect(snsSender.setEndpointAttributes).toHaveBeenCalled(); + //expect(snsSender.publish).toHaveBeenCalled(); done(); }); }); it('can send to APNS with unknown identifier', (done) => { - var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint']); + var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint','setEndpointAttributes']); snsSender.createPlatformEndpoint.and.callFake(function (object, callback) { callback(null, {'EndpointArn': 'ARN'}); }); - snsSender.publish.and.callFake(function (object, callback) { + snsSender.setEndpointAttributes.and.callFake(function (params, callback) { callback(null, '123'); }); + + //snsSender.publish.and.callFake(function (object, callback) { + // callback(null, '123'); + //}); snsPushAdapter.sns = snsSender; @@ -335,23 +363,28 @@ describe('SNSPushAdapter', () => { snsPushAdapter = new SNSPushAdapter(pushConfig); - var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint']); + var snsSender = jasmine.createSpyObj('sns', ['publish', 'createPlatformEndpoint','setEndpointAttributes']); snsSender.createPlatformEndpoint.and.callFake(function (object, callback) { callback(null, {'EndpointArn': 'APNS_PROD_ID'}); }); - - snsSender.publish.and.callFake(function (object, callback) { + + snsSender.setEndpointAttributes.and.callFake(function (params, callback) { callback(null, '123'); }); + //snsSender.publish.and.callFake(function (object, callback) { + // callback(null, '123'); + //}); snsPushAdapter.sns = snsSender; var promises = snsPushAdapter.sendToAPNS({"test": "hello"}, [makeDevice("ios", "beta.parseplatform.myapp")]); expect(promises.length).toEqual(1); Promise.all(promises).then(function () { - expect(snsSender.publish).toHaveBeenCalled(); - var args = snsSender.publish.calls.first().args[0]; + expect(snsSender.setEndpointAttributes).toHaveBeenCalled(); + var args = snsSender.setEndpointAttributes.calls.first().args[0]; + //expect(snsSender.publish).toHaveBeenCalled(); + //var args = snsSender.publish.calls.first().args[0]; expect(args.Message).toEqual("{\"APNS_SANDBOX\":\"{}\"}"); done(); }); diff --git a/src/SNSPushAdapter.js b/src/SNSPushAdapter.js index cc5fbf9..d3e98d7 100644 --- a/src/SNSPushAdapter.js +++ b/src/SNSPushAdapter.js @@ -189,7 +189,6 @@ SNSPushAdapter.prototype.exchangeTokenPromise = function (device, platformARN) { * Send the Message, MessageStructure, and Target Amazon Resource Number (ARN) to SNS * @param arn Amazon Resource ID * @param payload JSON-encoded message - * @param device Device info (used for returning push status) * @returns {Parse.Promise} */ SNSPushAdapter.prototype.sendSNSPayload = function (arn, payload, device) { @@ -199,6 +198,11 @@ SNSPushAdapter.prototype.sendSNSPayload = function (arn, payload, device) { MessageStructure: 'json', TargetArn: arn }; + + if (device.deviceToken.startsWith("arn")) { + object.TargetArn = undefined; + object.TopicArn = device.deviceToken; + } return new Parse.Promise((resolve, reject) => { var response = { @@ -207,24 +211,72 @@ SNSPushAdapter.prototype.sendSNSPayload = function (arn, payload, device) { deviceToken: device.deviceToken.toString('hex') } }; + + // publish to topic + if (object.TopicArn) { + return this.sns.publish(object, (err, data) => { + if (err != null) { + log.error(LOG_PREFIX, "Error sending push " + err); + response.transmitted = false; + if (err.stack) { + response.response = err.stack; + } + return reject(response); + } - this.sns.publish(object, (err, data) => { + if (data && data.MessageId) { + log.verbose(LOG_PREFIX, "Successfully sent push to " + data.MessageId); + } + + response.transmitted = true; + response.response = data; + resolve(response); + }); + } + + /* + * Amazon SNS will set Endpoint to false when a notification service indicates to Amazon SNS + * that the endpoint is invalid. We need to set it back to true + */ + + var params = { + Attributes: { + Enabled: "true", + }, + EndpointArn: arn + }; + + this.sns.setEndpointAttributes(params, (err, data) => { if (err != null) { - log.error(LOG_PREFIX, "Error sending push " + err); + log.error(LOG_PREFIX, "Error enabling Endpoints " + err); response.transmitted = false; if (err.stack) { response.response = err.stack; } return reject(response); } - - if (data && data.MessageId) { - log.verbose(LOG_PREFIX, "Successfully sent push to " + data.MessageId); + + // send the push after re-enabling Endpoint + if (data) { + this.sns.publish(object, (err, data) => { + if (err != null) { + log.error(LOG_PREFIX, "Error sending push " + err); + response.transmitted = false; + if (err.stack) { + response.response = err.stack; + } + return reject(response); + } + + if (data && data.MessageId) { + log.verbose(LOG_PREFIX, "Successfully sent push to " + data.MessageId); + } + + response.transmitted = true; + response.response = data; + resolve(response); + }); } - - response.transmitted = true; - response.response = data; - resolve(response); }); }); } @@ -234,6 +286,12 @@ SNSPushAdapter.prototype.sendSNSPayload = function (arn, payload, device) { */ SNSPushAdapter.prototype.send = function (data, installations) { + if(installations.arn){ + installations = installations.arn; + for (installation of installations){ + installation.deviceToken = installation.topicArn; + } + } let deviceMap = utils.classifyInstallations(installations, this.availablePushTypes); let sendPromises = Object.keys(deviceMap).forEach((pushType) => {