Skip to content

feat(fcm): Added support for specifying the analytics label for notifications. #597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3579,6 +3579,7 @@ type BaseMessage = {
android?: admin.messaging.AndroidConfig;
webpush?: admin.messaging.WebpushConfig;
apns?: admin.messaging.ApnsConfig;
fcmOptions?: admin.messaging.FcmOptions;
};

interface TokenMessage extends BaseMessage {
Expand Down Expand Up @@ -3641,6 +3642,11 @@ declare namespace admin.messaging {
* Android notification to be included in the message.
*/
notification?: AndroidNotification;

/**
* Options for features provided by the FCM SDK for Android.
*/
fcmOptions?: AndroidFcmOptions;
}

/**
Expand Down Expand Up @@ -3726,6 +3732,17 @@ declare namespace admin.messaging {
channelId?: string;
}

/**
* Represents options for features provided by the FCM SDK for Android.
*/
interface AndroidFcmOptions {

/**
* The label associated with the message's analytics data.
*/
analyticsLabel?: string;
}

/**
* Represents the APNs-specific options that can be included in an
* {@link admin.messaging.Message}. Refer to
Expand All @@ -3743,6 +3760,11 @@ declare namespace admin.messaging {
* An APNs payload to be included in the message.
*/
payload?: ApnsPayload;

/**
* Options for features provided by the FCM SDK for iOS.
*/
fcmOptions?: ApnsFcmOptions;
}
/**
* Represents the payload of an APNs message. Mainly consists of the `aps`
Expand Down Expand Up @@ -3841,6 +3863,28 @@ declare namespace admin.messaging {
volume?: number;
}

/**
* Represents options for features provided by the FCM SDK for iOS.
*/
interface ApnsFcmOptions {

/**
* The label associated with the message's analytics data.
*/
analyticsLabel?: string;
}

/**
* Represents platform-independent options for features provided by the FCM SDKs.
*/
interface FcmOptions {

/**
* The label associated with the message's analytics data.
*/
analyticsLabel?: string;
}


/**
* A notification that can be included in {@link admin.messaging.Message}.
Expand Down
77 changes: 77 additions & 0 deletions src/messaging/messaging-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface BaseMessage {
android?: AndroidConfig;
webpush?: WebpushConfig;
apns?: ApnsConfig;
fcmOptions?: FcmOptions;
}

interface TokenMessage extends BaseMessage {
Expand Down Expand Up @@ -60,6 +61,10 @@ export interface Notification {
body?: string;
}

export interface FcmOptions {
analyticsLabel?: string;
}

export interface WebpushConfig {
headers?: {[key: string]: string};
data?: {[key: string]: string};
Expand Down Expand Up @@ -97,6 +102,7 @@ export interface WebpushNotification {
export interface ApnsConfig {
headers?: {[key: string]: string};
payload?: ApnsPayload;
fcmOptions?: ApnsFcmOptions;
}

export interface ApnsPayload {
Expand Down Expand Up @@ -135,13 +141,18 @@ export interface ApsAlert {
launchImage?: string;
}

export interface ApnsFcmOptions {
analyticsLabel?: string;
}

export interface AndroidConfig {
collapseKey?: string;
priority?: ('high' | 'normal');
ttl?: number;
restrictedPackageName?: string;
data?: {[key: string]: string};
notification?: AndroidNotification;
fcmOptions?: AndroidFcmOptions;
}

export interface AndroidNotification {
Expand All @@ -159,6 +170,10 @@ export interface AndroidNotification {
channelId?: string;
}

export interface AndroidFcmOptions {
analyticsLabel?: string;
}

/* Payload for data messages */
export interface DataMessagePayload {
[key: string]: string;
Expand Down Expand Up @@ -291,6 +306,7 @@ export function validateMessage(message: Message) {
validateAndroidConfig(message.android);
validateWebpushConfig(message.webpush);
validateApnsConfig(message.apns);
validateFcmOptions(message.fcmOptions);
}

/**
Expand Down Expand Up @@ -345,8 +361,49 @@ function validateApnsConfig(config: ApnsConfig) {
}
validateStringMap(config.headers, 'apns.headers');
validateApnsPayload(config.payload);
validateApnsFcmOptions(config.fcmOptions);
}

/**
* Checks if the given ApnsFcmOptions object is valid.
*
* @param {ApnsFcmOptions} fcmOptions An object to be validated.
*/
function validateApnsFcmOptions(fcmOptions: ApnsFcmOptions) {
if (typeof fcmOptions === 'undefined') {
return;
} else if (!validator.isNonNullObject(fcmOptions)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
}

if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
}
}

/**
* Checks if the given FcmOptions object is valid.
*
* @param {FcmOptions} fcmOptions An object to be validated.
*/
function validateFcmOptions(fcmOptions: FcmOptions) {
if (typeof fcmOptions === 'undefined') {
return;
} else if (!validator.isNonNullObject(fcmOptions)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
}

if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
}
}



/**
* Checks if the given ApnsPayload object is valid. The object must have a valid aps value.
*
Expand Down Expand Up @@ -535,6 +592,7 @@ function validateAndroidConfig(config: AndroidConfig) {
}
validateStringMap(config.data, 'android.data');
validateAndroidNotification(config.notification);
validateAndroidFcmOptions(config.fcmOptions);

const propertyMappings = {
collapseKey: 'collapse_key',
Expand Down Expand Up @@ -585,3 +643,22 @@ function validateAndroidNotification(notification: AndroidNotification) {
};
renameProperties(notification, propertyMappings);
}

/**
* Checks if the given AndroidFcmOptions object is valid.
*
* @param {AndroidFcmOptions} fcmOptions An object to be validated.
*/
function validateAndroidFcmOptions(fcmOptions: AndroidFcmOptions) {
if (typeof fcmOptions === 'undefined') {
return;
} else if (!validator.isNonNullObject(fcmOptions)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
}

if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
}
}
38 changes: 38 additions & 0 deletions test/unit/messaging/messaging.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2469,6 +2469,24 @@ describe('Messaging', () => {
messaging.send({data: arg, topic: 'test'});
}).to.throw('data must be a non-null object');
});

it(`should throw given invalid fcmOptions: ${JSON.stringify(arg)}`, () => {
expect(() => {
messaging.send({fcmOptions: arg, topic: 'test'});
}).to.throw('fcmOptions must be a non-null object');
});

it(`should throw given invalid AndroidFcmOptions: ${JSON.stringify(arg)}`, () => {
expect(() => {
messaging.send({android: {fcmOptions: arg}, topic: 'test'});
}).to.throw('fcmOptions must be a non-null object');
});

it(`should throw given invalid ApnsFcmOptions: ${JSON.stringify(arg)}`, () => {
expect(() => {
messaging.send({apns: {fcmOptions: arg}, topic: 'test'});
}).to.throw('fcmOptions must be a non-null object');
});
});

const invalidDataMessages: any[] = [
Expand Down Expand Up @@ -2750,6 +2768,14 @@ describe('Messaging', () => {
},
},
},
{
label: 'Generic fcmOptions message',
req: {
fcmOptions: {
analyticsLabel: 'test.analytics',
},
},
},
{
label: 'Android data message',
req: {
Expand Down Expand Up @@ -2852,6 +2878,9 @@ describe('Messaging', () => {
bodyLocArgs: ['arg1', 'arg2'],
channelId: 'test.channel',
},
fcmOptions: {
analyticsLabel: 'test.analytics',
},
},
},
expectedReq: {
Expand All @@ -2878,6 +2907,9 @@ describe('Messaging', () => {
body_loc_args: ['arg1', 'arg2'],
channel_id: 'test.channel',
},
fcmOptions: {
analyticsLabel: 'test.analytics',
},
},
},
},
Expand Down Expand Up @@ -2999,6 +3031,9 @@ describe('Messaging', () => {
customKey1: 'custom.value',
customKey2: {nested: 'value'},
},
fcmOptions: {
analyticsLabel: 'test.analytics',
},
},
},
expectedReq: {
Expand Down Expand Up @@ -3032,6 +3067,9 @@ describe('Messaging', () => {
customKey1: 'custom.value',
customKey2: {nested: 'value'},
},
fcmOptions: {
analyticsLabel: 'test.analytics',
},
},
},
},
Expand Down