Update apnsservice to parse template in APN compatible way

This commit is contained in:
Todd Reifsteck 2014-08-05 14:11:46 -07:00
Родитель bbdd7858fb
Коммит 4d8aeab574
3 изменённых файлов: 613 добавлений и 268 удалений

Просмотреть файл

@ -49,11 +49,12 @@ function ApnsService(notificationHubService) {
* If null it will broadcast to all registrations in this hub
* @param {object|string} payload The message's JSON payload as specified below.
* If the payload is a string, follow the APNS format as in https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [payload.badge] The number to display over the app icon.
* @param {string} [payload.alert] The alert text.
* @param {string} [payload.sound] The sound file name.
* @param {object} [payload.payload] The payload object that contains the notification text.
* @param {date} [payload.expiry] The expiration date. (in W3C DTF, YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00))
* @param {object} [payload.aps] If the 'aps' member is provided, the object is delivered to APNS as-is after expiry is processed. The object is assumed to follow the APNS format at https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [payload.badge] If the 'aps' member is not provided, the number to display over the app icon.
* @param {string} [payload.alert] If the 'aps' member is not provided, the alert text.
* @param {string} [payload.sound] If the 'aps' member is not provided, the sound file name.
* @param {object} [payload.payload] If the 'aps' member is not provided, the payload object that contains the notification text.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise, `response`
* will contain information related to this operation.
@ -89,28 +90,16 @@ ApnsService.prototype.send = function (tags, payload, callback) {
headers[HeaderConstants.SERVICE_BUS_NOTIFICATION_TAGS] = tags;
}
payload = _.clone(payload);
if (payload.expiry) {
var expiry = new Date(payload.expiry);
headers[HeaderConstants.SERVICE_BUS_NOTIFICATION_APNS_EXPIRY] = expiry.toISOString();
delete payload.expiry;
}
if (!_.isString(payload)) {
if (!payload.aps) {
payload = { aps: payload };
payload = _.clone(payload);
if (payload.aps.payload) {
Object.keys(payload.aps.payload).forEach(function (innerPayloadMember) {
payload[innerPayloadMember] = payload.aps.payload[innerPayloadMember];
});
delete payload.aps.payload;
}
if (payload.expiry) {
var expiry = new Date(payload.expiry);
headers[HeaderConstants.SERVICE_BUS_NOTIFICATION_APNS_EXPIRY] = expiry.toISOString();
delete payload.expiry;
}
payload = JSON.stringify(payload);
payload = this._formatPayload(payload);
}
headers[HeaderConstants.CONTENT_TYPE] = 'application/json;charset="utf-8"';
@ -176,11 +165,12 @@ ApnsService.prototype.createOrUpdateNativeRegistration = function (registrationI
* @param {string|array} tags The tags.
* @param {object|string} template The message's JSON payload as specified below.
* If the payload is a string, follow the APNS format as in https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [template.badge] The number to display over the app icon.
* @param {string} [template.alert] The alert text.
* @param {string} [template.sound] The sound file name.
* @param {object} [template.payload] The payload object that contains the notification text.
* @param {date} [template.expiry] The expiration date.
* @param {object} [template.aps] If the 'aps' member is provided, the registration is delivered to NotifcationHub as-is after expiry is processed. The object is assumed to follow the APNS format at https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [template.badge] If the 'aps' member is not provided, the number to display over the app icon.
* @param {string} [template.alert] If the 'aps' member is not provided, the alert text.
* @param {string} [template.sound] If the 'aps' member is not provided, the sound file name.
* @param {object} [template.payload] If the 'aps' member is not provided, the payload object that contains the notification text.
* @param {object} [options] The request options.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise, `response`
@ -212,11 +202,12 @@ ApnsService.prototype.createTemplateRegistration = function (token, tags, templa
* @param {string} token The device token.
* @param {object|string} template The message's JSON payload as specified below.
* If the payload is a string, follow the APNS format as in https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [template.badge] The number to display over the app icon.
* @param {string} [template.alert] The alert text.
* @param {string} [template.sound] The sound file name.
* @param {object} [template.payload] The payload object that contains the notification text.
* @param {date} [template.expiry] The expiration date.
* @param {object} [template.aps] If the 'aps' member is provided, the registration is delivered to NotifcationHub as-is after expiry is processed. The object is assumed to follow the APNS format at https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [template.badge] If the 'aps' member is not provided, the number to display over the app icon.
* @param {string} [template.alert] If the 'aps' member is not provided, the alert text.
* @param {string} [template.sound] If the 'aps' member is not provided, the sound file name.
* @param {object} [template.payload] If the 'aps' member is not provided, the payload object that contains the notification text.
* @param {object} [options] The request options.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise, `response`
@ -249,11 +240,12 @@ ApnsService.prototype.createOrUpdateTemplateRegistration = function (registratio
* @param {string} token The device token.
* @param {object|string} template The message's JSON payload as specified below.
* If the payload is a string, follow the APNS format as in https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [template.badge] The number to display over the app icon.
* @param {string} [template.alert] The alert text.
* @param {string} [template.sound] The sound file name.
* @param {object} [template.payload] The payload object that contains the notification text.
* @param {date} [template.expiry] The expiration date.
* @param {object} [template.aps] If the 'aps' member is provided, the registration is delivered to NotifcationHub as-is after expiry is processed. The object is assumed to follow the APNS format at https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW1
* @param {number} [template.badge] If the 'aps' member is not provided, the number to display over the app icon.
* @param {string} [template.alert] If the 'aps' member is not provided, the alert text.
* @param {string} [template.sound] If the 'aps' member is not provided, the sound file name.
* @param {object} [template.payload] If the 'aps' member is not provided, the payload object that contains the notification text.
* @param {object} [options] The request options.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise, `response`
@ -359,33 +351,22 @@ ApnsService.prototype._createBody = function (elementName, token, tags, template
if (template) {
var payload = _.clone(template);
if (payload.payload) {
Object.keys(payload.payload).forEach(function (property) {
payload[property] = payload.payload[property];
});
delete payload.payload;
}
var expiry;
if (!_.isString(payload)) {
var expiry;
if (payload.expiry) {
expiry = payload.expiry;
delete payload.expiry;
}
if (!payload.aps) {
payload = { aps: payload };
}
payload = JSON.stringify(payload);
registration.BodyTemplate = '<![CDATA[' + payload + ']]>';
if (expiry) {
registration['Expiry'] = expiry;
}
payload = this._formatPayload(payload);
}
registration.BodyTemplate = '<![CDATA[' + payload + ']]>';
// Expiry member must be set after BodyTemplate
if (expiry) {
registration.Expiry = expiry;
}
}
@ -406,4 +387,20 @@ ApnsService.prototype._createTemplateBody = function (token, tags, template, opt
return this._createBody('AppleTemplateRegistrationDescription', token, tags, template, options);
};
module.exports = ApnsService;
ApnsService.prototype._formatPayload = function (payload) {
if (!payload.aps) {
payload = { aps: payload };
if (payload.aps.payload) {
Object.keys(payload.aps.payload).forEach(function (innerPayloadMember) {
payload[innerPayloadMember] = payload.aps.payload[innerPayloadMember];
});
delete payload.aps.payload;
}
}
return JSON.stringify(payload);
};
module.exports = ApnsService;

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -57,12 +57,13 @@ describe('APNS notifications registrations', function () {
beforeEach(function (done) {
suiteUtil.setupTest(function () {
service.listNotificationHubs(function (err, hubs) {
should.not.exist(err);
var xplatHubs = hubs.filter(function (hub) {
return hub.NotificationHubName.substr(0, hubNamePrefix.length) === hubNamePrefix;
});
_.each(xplatHubs, function (hub) {
service.deleteNotificationHub(hub.NotificationHubName, function () {});
service.deleteNotificationHub(hub.NotificationHubName, function () { });
});
done();
@ -73,7 +74,7 @@ describe('APNS notifications registrations', function () {
afterEach(function (done) {
// Schedule deleting notification hubs
_.each(hubNames, function (notificationHub) {
service.deleteNotificationHub(notificationHub, function () {});
service.deleteNotificationHub(notificationHub, function () { });
});
suiteUtil.baseTeardownTest(done);
@ -90,12 +91,12 @@ describe('APNS notifications registrations', function () {
suiteUtil.setupService(notificationHubService);
service.createNotificationHub(hubName, {
apns: {
ApnsCertificate: process.env.AZURE_APNS_CERTIFICATE,
CertificateKey: process.env.AZURE_APNS_CERTIFICATE_KEY,
Endpoint: 'pushtestservice2.cloudapp.net'
}
}, done);
apns: {
ApnsCertificate: process.env.AZURE_APNS_CERTIFICATE,
CertificateKey: process.env.AZURE_APNS_CERTIFICATE_KEY,
Endpoint: 'pushtestservice2.cloudapp.net'
}
}, done);
});
describe('native', function () {
@ -118,7 +119,7 @@ describe('APNS notifications registrations', function () {
describe('list', function () {
beforeEach(function (done) {
notificationHubService.apns.createNativeRegistration(tokenId, [ 'mytag'], done);
notificationHubService.apns.createNativeRegistration(tokenId, ['mytag'], done);
});
it('should work without filtering', function (done) {
@ -172,6 +173,7 @@ describe('APNS notifications registrations', function () {
});
it('should work', function (done) {
var executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.createTemplateRegistration(
tokenId,
null,
@ -182,11 +184,14 @@ describe('APNS notifications registrations', function () {
should.not.exist(error);
registrationId = registration.RegistrationId;
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(alertMessage1)"}}]]></BodyTemplate>');
done();
});
});
});
it('should work when payload matches APNS specs', function (done) {
var executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.createTemplateRegistration(
tokenId,
null,
@ -199,15 +204,40 @@ describe('APNS notifications registrations', function () {
should.not.exist(error);
registrationId = registration.RegistrationId;
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(alertMessage1)"}}]]></BodyTemplate>');
done();
});
});
});
it('should work when payload matches APNS specs and has extra data', function (done) {
var executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.createTemplateRegistration(
tokenId,
null,
{
aps: {
alert: '$(alertMessage1)'
},
extraData: '$(data)'
},
function (error, registration) {
should.not.exist(error);
registrationId = registration.RegistrationId;
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(alertMessage1)"},"extraData":"$(data)"}]]></BodyTemplate>');
done();
});
});
});
describe('update alert', function () {
var registrationId;
var executeSpy;
beforeEach(function (done) {
executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.createTemplateRegistration(
tokenId,
null,
@ -218,6 +248,8 @@ describe('APNS notifications registrations', function () {
should.not.exist(error);
registrationId = registration.RegistrationId;
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(alertMessage1)"}}]]></BodyTemplate>');
done();
});
});
@ -227,6 +259,8 @@ describe('APNS notifications registrations', function () {
});
it('should work', function (done) {
sandbox.restore();
executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.updateTemplateRegistration(
registrationId,
tokenId,
@ -237,6 +271,54 @@ describe('APNS notifications registrations', function () {
function (error) {
should.not.exist(error);
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(newAlertMessage1)"}}]]></BodyTemplate>');
done();
});
});
it('should work when payload member exists', function (done) {
sandbox.restore();
executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.updateTemplateRegistration(
registrationId,
tokenId,
null,
{
alert: '$(newAlertMessage1)',
payload: {
data1: '$(data1)',
data2: '$(data2)',
}
},
function (error) {
should.not.exist(error);
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(newAlertMessage1)"},"data1":"$(data1)","data2":"$(data2)"}]]></BodyTemplate>');
done();
});
});
it('should work when aps exists without modifying payload as extra data', function (done) {
sandbox.restore();
executeSpy = sandbox.spy(notificationHubService, '_executeRequest');
notificationHubService.apns.updateTemplateRegistration(
registrationId,
tokenId,
null,
{
aps: { alert: '$(newAlertMessage1)' },
payload: {
data1: '$(data1)',
data2: '$(data2)',
}
},
function (error) {
should.not.exist(error);
executeSpy.args[0][1].should.include('<BodyTemplate><![CDATA[{"aps":{"alert":"$(newAlertMessage1)"},"payload":{"data1":"$(data1)","data2":"$(data2)"}}]]></BodyTemplate>');
done();
});
});