Skip to content

Commit 1bf4f2a

Browse files
Merge branch 'master' into SER-2112-push-better-error-reporting-for-fcm
2 parents 3f13f72 + f5c1065 commit 1bf4f2a

File tree

9 files changed

+235
-157
lines changed

9 files changed

+235
-157
lines changed

CHANGELOG.md

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
## Version 24.05.16
2+
Fixes:
3+
- [core] Replaced "Users" with "Sessions" label on technology home widgets
4+
- [push] Replaced push plugin with an earlier version of the plugin
5+
6+
Enterprise fixes:
7+
- [license] Fixed bug with MAU type of licenses that would prevent the server from starting
8+
- [nps] Fixed bug where it was possible to submit empty nps surveys
9+
- [ratings] Fixed bug with user consent
10+
11+
Security:
12+
- Bumped cookie-parser from 1.4.6 to 1.4.7
13+
- Bumped express-rate-limit from 7.4.0 to 7.4.1
14+
- Bumped moment-timezone from 0.5.45 to 0.5.46
15+
- Bumped sass from 1.79.3 to 1.79.4
16+
117
## Version 24.05.15
218
Enterprise fixes:
319
- [nps] Fixed UI issues in the widget editor related to the "user consent" section

plugins/push/api/api.js

+13-11
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@ plugins.setConfigs(FEATURE_NAME, {
6363
pool_pushes: 400, // object mode streams high water mark
6464
pool_bytes: 10000, // bytes mode streams high water mark
6565
pool_concurrency: 5, // max number of same type connections
66-
pool_pools: 10 // max number of connections in total
66+
pool_pools: 10, // max number of connections in total
67+
default_content_available: false, // sets content-available: 1 by default for ios
6768
});
6869

6970
plugins.internalEvents.push('[CLY]_push_sent');
7071
plugins.internalEvents.push('[CLY]_push_action');
7172
plugins.internalDrillEvents.push('[CLY]_push_action');
73+
plugins.internalDrillEvents.push('[CLY]_push_sent');
7274

7375

7476
plugins.register('/worker', function() {
@@ -217,7 +219,7 @@ plugins.register('/i', async ob => {
217219

218220
/**
219221
* Handy function for handling api calls (see apis obj above)
220-
*
222+
*
221223
* @param {object} apisObj apis.i or apis.o
222224
* @param {object} ob object from pluginManager ({params, qstring, ...})
223225
* @returns {boolean} true if the call has been handled
@@ -264,7 +266,7 @@ function apiCall(apisObj, ob) {
264266

265267
/**
266268
* Wrap push endpoint catching any push-specific errors from it
267-
*
269+
*
268270
* @param {string} method endpoint name
269271
* @param {function} fn actual endpoint returning a promise
270272
* @returns {function} CRUD callback
@@ -357,7 +359,7 @@ plugins.register('/i/app_users/export', ({app_id, uids, export_commands, dbargs,
357359

358360
/**
359361
* @apiDefine PushMessageBody
360-
*
362+
*
361363
* @apiBody {ObjectID} app Application ID
362364
* @apiBody {String[]} platforms Array of platforms to send to
363365
* @apiBody {String="draft"} [status] Message status, only set to draft when creating or editing a draft message, don't set otherwise
@@ -376,9 +378,9 @@ plugins.register('/i/app_users/export', ({app_id, uids, export_commands, dbargs,
376378
* @apiBody {Number} [triggers.time] [only for event, cohort triggers] Time in ms since 00:00 in case event or cohort message is to be sent in users' timezones
377379
* @apiBody {Boolean} [triggers.reschedule] [only for event, cohort triggers] Allow rescheduling to next day if it's too late to send on scheduled day
378380
* @apiBody {Number} [triggers.delay] [only for event, cohort triggers] Milliseconds to delay sending of event or cohort message
379-
* @apiBody {Number} [triggers.cap] [only for event, cohort & api triggers] Set maximum number of notifications sent to a particular user
381+
* @apiBody {Number} [triggers.cap] [only for event, cohort & api triggers] Set maximum number of notifications sent to a particular user
380382
* @apiBody {Number} [triggers.sleep] [only for event, cohort & api triggers] Set minimum time in ms between two notifications for a particular user (a notification is discarded if it's less than that)
381-
* @apiBody {String[]} [triggers.events] [only for event trigger] Event keys
383+
* @apiBody {String[]} [triggers.events] [only for event trigger] Event keys
382384
* @apiBody {String[]} [triggers.cohorts] [only for cohort trigger] Cohort ids
383385
* @apiBody {Boolean} [triggers.entry] [only for cohort trigger] Send on cohort entry (true) or exit (false)
384386
* @apiBody {Boolean} [triggers.cancels] [only for cohort trigger] A notification is to be discarded if user exits cohort (when entry = true) before notification is sent
@@ -405,7 +407,7 @@ plugins.register('/i/app_users/export', ({app_id, uids, export_commands, dbargs,
405407

406408
/**
407409
* @apiDefine PushMessage
408-
*
410+
*
409411
* @apiSuccess {ObjectID} _id Message ID
410412
* @apiSuccess {ObjectID} app Application ID
411413
* @apiSuccess {String[]} platforms Array of platforms to send to
@@ -426,9 +428,9 @@ plugins.register('/i/app_users/export', ({app_id, uids, export_commands, dbargs,
426428
* @apiSuccess {Number} [triggers.time] [only for event, cohort triggers] Time in ms since 00:00 in case event or cohort message is to be sent in users' timezones
427429
* @apiSuccess {Boolean} [triggers.reschedule] [only for event, cohort triggers] Allow rescheduling to next day if it's too late to send on scheduled day
428430
* @apiSuccess {Number} [triggers.delay] [only for event, cohort triggers] Milliseconds to delay sending of event or cohort message
429-
* @apiSuccess {Number} [triggers.cap] [only for event, cohort & api triggers] Set maximum number of notifications sent to a particular user
431+
* @apiSuccess {Number} [triggers.cap] [only for event, cohort & api triggers] Set maximum number of notifications sent to a particular user
430432
* @apiSuccess {Number} [triggers.sleep] [only for event, cohort & api triggers] Set minimum time in ms between two notifications for a particular user (a notification is discarded if it's less than that)
431-
* @apiSuccess {String[]} [triggers.events] [only for event trigger] Event keys
433+
* @apiSuccess {String[]} [triggers.events] [only for event trigger] Event keys
432434
* @apiSuccess {String[]} [triggers.cohorts] [only for cohort trigger] Cohort ids
433435
* @apiSuccess {Boolean} [triggers.entry] [only for cohort trigger] Send on cohort entry (true) or exit (false)
434436
* @apiSuccess {Boolean} [triggers.cancels] [only for cohort trigger] A notification is to be discarded if user exits cohort (when entry = true) before notification is sent
@@ -457,7 +459,7 @@ plugins.register('/i/app_users/export', ({app_id, uids, export_commands, dbargs,
457459
* @apiSuccess {Object} [result.sent] Number notifications sent successfully
458460
* @apiSuccess {Object} [result.actioned] Number notifications with positive user reactions (notification taps & button clicks)
459461
* @apiSuccess {Object} [result.errored] Number notifications which weren't sent due to various errors
460-
* @apiSuccess {Object[]} [result.lastErrors] Array of last 10 errors
462+
* @apiSuccess {Object[]} [result.lastErrors] Array of last 10 errors
461463
* @apiSuccess {Object[]} [result.lastRuns] Array of last 10 sending runs
462464
* @apiSuccess {Date} [result.next] Next sending date
463465
* @apiSuccess {Object} [result.subs] Sub results - a map of subresult key to Result object. Subresults are used to store platform and locale specific results.
@@ -488,4 +490,4 @@ plugins.register('/i/app_users/export', ({app_id, uids, export_commands, dbargs,
488490
* @apiSuccess {Boolean} [info.demo] Whether the message was created using populator plugin
489491
*/
490492

491-
module.exports = PUSH;
493+
module.exports = PUSH;

plugins/push/api/send/platforms/i.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ const map = {
505505
template.result.aps.alert = template.result.aps.alert || {};
506506
template.result.aps.alert.subtitle = specific.subtitle;
507507
}
508+
if (specific.setContentAvailable) {
509+
template.result.aps["content-available"] = 1;
510+
}
508511
}
509512
},
510513
};
@@ -549,6 +552,8 @@ class APN extends Base {
549552
':method': 'POST',
550553
':scheme': 'https',
551554
':authority': authority,
555+
// this is being added before the actual request depending on weather message have setContentAvailable
556+
// "apns-priority": 5,
552557
[HTTP2.sensitiveHeaders]: ['authorization', ':path', 'apns-id', 'apns-expiration', 'apns-collapse-id']
553558
};
554559
this.headersSecondWithToken = token => {
@@ -660,7 +665,22 @@ class APN extends Base {
660665
}
661666

662667
let content = this.template(p.m).compile(p),
663-
stream = this.session.request(this.headersSecondWithToken(p.t)),
668+
reqHeaders = self.headersSecondWithToken(p.t);
669+
// find if we need to add the priority header (check if content-available set)
670+
delete reqHeaders["apns-priority"];
671+
const message = self.messages[p.m];
672+
if (message && Array.isArray(message.contents)) {
673+
const contentItem = message.contents.find(cont => Array.isArray(cont.specific));
674+
if (contentItem) {
675+
const obj = contentItem.specific.find(cont => cont.setContentAvailable !== undefined);
676+
if (obj && obj.setContentAvailable) {
677+
reqHeaders["apns-priority"] = 5;
678+
}
679+
}
680+
}
681+
// =======0========000=================0========000=================0========0
682+
console.log(JSON.stringify(reqHeaders, null, 2), JSON.stringify(content, null, 2));
683+
let stream = this.session.request(reqHeaders),
664684
status,
665685
data = '';
666686
stream.on('error', err => {

plugins/push/frontend/public/javascripts/countly.models.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@
246246
badgeNumber: "",
247247
onClickURL: "",
248248
json: null,
249-
userData: []
249+
userData: [],
250+
setContentAvailable: false,
250251
},
251252
android: {
252253
mediaURL: "",
@@ -1157,9 +1158,19 @@
11571158
};
11581159
},
11591160
mapIOSSettings: function(iosSettingsDto) {
1161+
let subtitle, setContentAvailable;
1162+
if (iosSettingsDto && Array.isArray(iosSettingsDto.specific)) {
1163+
let subtitleItem = iosSettingsDto.specific.find(i => i.subtitle !== undefined);
1164+
if (subtitleItem) {
1165+
subtitle = countlyPushNotification.helper.decodeMessage(subtitleItem.subtitle || "");
1166+
}
1167+
let contentAvailableItem = iosSettingsDto.specific.find(i => i.setContentAvailable !== undefined);
1168+
setContentAvailable = contentAvailableItem.setContentAvailable;
1169+
}
11601170
return {
11611171
// NOte: subtitle will reside at index zero for now. There are no other platform specifics
1162-
subtitle: iosSettingsDto && iosSettingsDto.specific && iosSettingsDto.specific[0] && countlyPushNotification.helper.decodeMessage(iosSettingsDto.specific[0].subtitle || ""),
1172+
subtitle,
1173+
setContentAvailable,
11631174
soundFilename: iosSettingsDto && iosSettingsDto.sound || "",
11641175
badgeNumber: iosSettingsDto && iosSettingsDto.badge && iosSettingsDto.badge.toString(),
11651176
json: iosSettingsDto && iosSettingsDto.data || null,
@@ -1756,12 +1767,21 @@
17561767
result.url = countlyCommon.decodeHtml(iosSettings.onClickURL);
17571768
}
17581769
if (iosSettings.subtitle && options.settings[PlatformEnum.IOS].isSubtitleEnabled) {
1759-
result.specific = [{subtitle: iosSettings.subtitle}];
1770+
if (!result.specific) {
1771+
result.specific = [];
1772+
}
1773+
result.specific.push({ subtitle: iosSettings.subtitle });
17601774
}
17611775
if (model.settings[PlatformEnum.IOS].mediaURL && options.settings[PlatformEnum.IOS].isMediaURLEnabled && model.messageType === MessageTypeEnum.CONTENT) {
17621776
result.media = countlyCommon.decodeHtml(model.settings[PlatformEnum.IOS].mediaURL);
17631777
result.mediaMime = model.settings[PlatformEnum.IOS].mediaMime;
17641778
}
1779+
if (options.settings[PlatformEnum.IOS].isContentAvailableSet) {
1780+
if (!result.specific) {
1781+
result.specific = [];
1782+
}
1783+
result.specific.push({ setContentAvailable: options.settings[PlatformEnum.IOS].isContentAvailableSet });
1784+
}
17651785
return result;
17661786
},
17671787
mapAndroidSettings: function(model, options) {

plugins/push/frontend/public/javascripts/countly.views.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable no-console */
2-
/* global countlyVue,app,CV,countlyPushNotification,countlyPushNotificationComponent,CountlyHelpers,countlyCommon,countlyGlobal,countlyAuth,countlyGraphNotesCommon*/
2+
/* global countlyVue,countlyPlugins,app,CV,countlyPushNotification,countlyPushNotificationComponent,CountlyHelpers,countlyCommon,countlyGlobal,countlyAuth,countlyGraphNotesCommon*/
33

44
(function() {
55

@@ -51,6 +51,7 @@
5151
isOnClickURLEnabled: false,
5252
isJsonEnabled: false,
5353
isUserDataEnabled: false,
54+
isContentAvailableSet: false,
5455
},
5556
android: {
5657
isMediaURLEnabled: false,
@@ -134,7 +135,7 @@
134135
selectedLocalizationFilter: countlyPushNotification.service.DEFAULT_LOCALIZATION_VALUE,
135136
isConfirmed: false,
136137
expandedPlatformSettings: [],
137-
settings: JSON.parse(JSON.stringify(InitialPushNotificationDrawerSettingsState)),
138+
settings: this.getInitialPushNotificationDrawerSettingsState(),
138139
userPropertiesIdCounter: 0,
139140
selectedUserPropertyId: null,
140141
isAddUserPropertyPopoverOpen: {
@@ -331,6 +332,14 @@
331332
}
332333
},
333334
methods: {
335+
getInitialPushNotificationDrawerSettingsState: function() {
336+
const _InitialPushNotificationDrawerSettingsState = JSON.parse(JSON.stringify(InitialPushNotificationDrawerSettingsState));
337+
const settings = countlyPlugins.getConfigsData();
338+
if (settings.push && settings.push.default_content_available) {
339+
_InitialPushNotificationDrawerSettingsState.ios.isContentAvailableSet = true;
340+
}
341+
return _InitialPushNotificationDrawerSettingsState;
342+
},
334343
previewCohorts: function(cohorts) {
335344
var selectedCohorts = this.cohortOptions.filter(function(cohort) {
336345
return cohorts.some(function(selectedCohortId) {
@@ -646,7 +655,7 @@
646655
title: false,
647656
content: false
648657
};
649-
this.settings = JSON.parse(JSON.stringify(InitialPushNotificationDrawerSettingsState));
658+
this.settings = this.getInitialPushNotificationDrawerSettingsState();
650659
this.pushNotificationUnderEdit = JSON.parse(JSON.stringify(countlyPushNotification.helper.getInitialModel(this.type)));
651660
},
652661
onClose: function() {
@@ -1046,6 +1055,7 @@
10461055
this.settings[this.PlatformEnum.IOS].isJsonEnabled = Boolean(this.pushNotificationUnderEdit.settings[this.PlatformEnum.IOS].json);
10471056
this.settings[this.PlatformEnum.IOS].isUserDataEnabled = Boolean(this.pushNotificationUnderEdit.settings[this.PlatformEnum.IOS].userData.length);
10481057
this.settings[this.PlatformEnum.IOS].isSubtitleEnabled = Boolean(this.pushNotificationUnderEdit.settings[this.PlatformEnum.IOS].subtitle);
1058+
this.settings[this.PlatformEnum.IOS].isContentAvailableSet = Boolean(this.pushNotificationUnderEdit.settings[this.PlatformEnum.IOS].setContentAvailable);
10491059
}
10501060
},
10511061
updateAndroidPlatformSettingsStateIfFound: function() {
@@ -2796,7 +2806,7 @@
27962806

27972807

27982808
/**
2799-
*
2809+
*
28002810
* @returns {Object} container data with create new message event handler
28012811
*/
28022812
function getCreateNewMessageEventContainerData() {
@@ -2812,7 +2822,7 @@
28122822
};
28132823
}
28142824
/**
2815-
*
2825+
*
28162826
* @returns {Object} container data with push notification drawer
28172827
*/
28182828
function getDrawerContainerData() {

plugins/push/frontend/public/localization/push.properties

+5-2
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ push-notification.media-url-platform-description = Add the URL for media specifi
201201
push-notification.subtitle = Subtitle
202202
push-notification.enter-your-subtitle = Enter your subtitle
203203
push-notification.subtitle-description = Add a subheading for your message.
204+
push-notification.set-content-available = Set content-available
205+
push-notification.set-content-available-description = Sets the apns-priority header to 5 and content-available property of request body to 1 for the IOS application to receive notifications while the app is in the background
204206
push-notification.on-click-url = On Click URL
205207
push-notification.enter-on-click-url = Enter on click URL
206208
push-notification.on-click-url-description = Add URL link that is opened when user taps a message in drawer.
@@ -307,7 +309,7 @@ push-notification-details.delivery-sub-header = Delivery
307309
push-notification-details.delivery-type = Delivery type
308310
push-notification-details.scheduled-for = Scheduled for
309311
push-notification-details.expiration-time = Expiration time
310-
push-notification-details.message-expires-after = Message expires after {0} day(s) and {1} hour(s)
312+
push-notification-details.message-expires-after = Message expires after {0} day(s) and {1} hour(s)
311313
push-notification-details.no-errors-found = No errors were found
312314
push-notification.users-targeted = Users Targeted
313315
push-notification.users-targeted-description = Total number of users targeted to receive the selected notification.
@@ -389,6 +391,7 @@ push.pool_pushes = Number of notifications in stream batches
389391
push.pool_bytes = Bytes in binary stream batches
390392
push.pool_concurrency = Maximum number of same type connections
391393
push.pool_pools = Maximum number of connections in total
394+
push.default_content_available = Set content-available to 1 by default for IOS
392395

393396
#Drawer from other views
394397
push-notification.send-message-to-users = Send message to users
@@ -414,7 +417,7 @@ push-notification.error-code.ExpiredCreds.desc = Push Notification credentials h
414417
push-notification.error-code.BadDeviceToken.desc = The push token received from your app by Countly Server was rejected by APNS as invalid. Please make sure you set `pushTestMode` property on the SDK's initial configuration correctly. Also please make sure provisioning profile (Development or Distribution) is valid, bundle ID is correct and entitlements are properly set.
415418
push-notification.error-code.MissingTopic.desc = The server failed to parse the certificate, please ensure you use universal certificate and contact support if you do.
416419
push-notification.error-code.DeviceTokenNotForTopic.desc = APNS certificate doesn't correspond to the Bundle ID of your application.
417-
push-notification.error-code.TopicDisallowed.desc = Sending Push Notifications to this topic is not allowed. Apple rejects sending Push Notifications to this topic. Most probably there is no such app in Certificates, Identifiers & Profiles portal.
420+
push-notification.error-code.TopicDisallowed.desc = Sending Push Notifications to this topic is not allowed. Apple rejects sending Push Notifications to this topic. Most probably there is no such app in Certificates, Identifiers & Profiles portal.
418421
push-notification.error-code.InvalidProviderToken.desc = Please check your Auth key file, Team ID & Bundle ID - some of those is invalid.
419422
push-notification.error-code.MissingRegistration.desc = Please contact customer support.
420423
push-notification.error-code.InvalidRegistration.desc = Probably you modified the way SDK handles FCM tokens. Please ensure you do it right or contact support.

0 commit comments

Comments
 (0)