Skip to content

Commit 2fd716b

Browse files
[SDK-448] Internal consent (#19)
* internal consent * fixed some typos * modified testing and logging * changelog entry * example * added comments to the example * example * changes to example * typo * fixed the example * tests added * eliminated old tests * grouped events * clean up * tests fixed * name change Co-authored-by: ArtursKadikis <kadikis.arturs@gmail.com>
1 parent 7b2db7b commit 2fd716b

13 files changed

Lines changed: 341 additions & 104 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Maximum stack trace lines per thread is now 30 by default.
99
- Maximum stack trace line length is now 200 by default.
1010
- ! Minor breaking change ! After initialization, the logging/debugging mode can only be changed with `Countly.setLoggingEnabled` instead of `Countly.debug` now.
11+
- When recording internal events with 'add_event', the respective feature consent will now be checked instead of just the 'events' consent.
1112
- Fixed a bug where the SDK throws a `Bulk user storage exception` due to a missing folder
1213
- Increased the default max event batch size to 100.
1314
- Logs are now color coded and indicate log levels.

examples/consent_removal_example.js

Lines changed: 0 additions & 26 deletions
This file was deleted.

lib/countly-bulk-user.js

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,16 @@ function CountlyBulkUser(conf) {
134134
this.check_consent = function(feature) {
135135
if (!conf.require_consent) {
136136
//we don't need to have specific consents
137+
cc.log(cc.logLevelEnums.INFO, "check_consent, Require consent is off. Giving consent for : [ " + feature + " ] feature.");
137138
return true;
138139
}
139-
if (consents[feature]) {
140-
return (consents[feature] && consents[feature].optin) ? true : false;
140+
if (consents[feature] && consents[feature].optin) {
141+
cc.log(cc.logLevelEnums.INFO, "check_consent, Giving consent for : [ " + feature + " ] feature.");
142+
return true;
143+
}
144+
if (consents[feature] && !consents[feature].optin) {
145+
cc.log(cc.logLevelEnums.ERROR, "check_consent, User is not optin. Consent refused for : [ " + feature + " ] feature.");
146+
return false;
141147
}
142148
else {
143149
cc.log(cc.logLevelEnums.WARNING, "check_consent, No feature available for " + feature);
@@ -221,7 +227,7 @@ function CountlyBulkUser(conf) {
221227
updateConsent();
222228
}
223229
}
224-
cc.log("Consent removal triggered.");
230+
cc.log(cc.logLevelEnums.DEBUG, "remove_consent, Consent removal triggered.");
225231

226232
}
227233
else {
@@ -247,7 +253,7 @@ function CountlyBulkUser(conf) {
247253
}
248254
}
249255
conf.server.add_bulk_request({consent: JSON.stringify(consentMessage)});
250-
cc.log("Consent update request has been sent to the queue.");
256+
cc.log(cc.logLevelEnums.DEBUG, "Consent update request has been sent to the queue.");
251257
}, 1000);
252258
};
253259

@@ -327,11 +333,41 @@ function CountlyBulkUser(conf) {
327333
* @param {number=} event.timestamp - timestamp when event occurred
328334
* @param {Object=} event.segmentation - object with segments key /values
329335
* @returns {module:lib/countly-bulk-user} instance
330-
**/
336+
**/
331337
this.add_event = function(event) {
332-
event.key = cc.truncateSingleValue(event.key, conf.maxKeyLength, "add_event");
333-
event.segmentation = cc.truncateObject(event.segmentation, conf.maxKeyLength, conf.maxValueSize, conf.maxSegmentationValues, "add_event");
334-
if (this.check_consent("events")) {
338+
cc.log('Trying to add the event: [ ' + event.key + ' ]');
339+
//initially no consent is given
340+
var respectiveConsent = false;
341+
//to match the internal events and their respective required consents. Sets respectiveConsent to true if the consent is given
342+
switch (event.key) {
343+
case cc.internalEventKeyEnums.NPS:
344+
respectiveConsent = this.check_consent('feedback');
345+
break;
346+
case cc.internalEventKeyEnums.SURVEY:
347+
respectiveConsent = this.check_consent('feedback');
348+
break;
349+
case cc.internalEventKeyEnums.STAR_RATING:
350+
respectiveConsent = this.check_consent('star-rating');
351+
break;
352+
case cc.internalEventKeyEnums.VIEW:
353+
respectiveConsent = this.check_consent('views');
354+
break;
355+
case cc.internalEventKeyEnums.ORIENTATION:
356+
respectiveConsent = this.check_consent('users');
357+
break;
358+
case cc.internalEventKeyEnums.PUSH_ACTION:
359+
respectiveConsent = this.check_consent('push');
360+
break;
361+
case cc.internalEventKeyEnums.ACTION:
362+
respectiveConsent = this.check_consent('clicks') || this.check_consent('scroll');
363+
break;
364+
default:
365+
respectiveConsent = this.check_consent('events');
366+
}
367+
368+
if (respectiveConsent) {
369+
event.key = cc.truncateSingleValue(event.key, conf.maxKeyLength, "add_event");
370+
event.segmentation = cc.truncateObject(event.segmentation, conf.maxKeyLength, conf.maxValueSize, conf.maxSegmentationValues, "add_event");
335371
conf.server.add_event(conf.device_id, event);
336372
}
337373
return this;
@@ -419,7 +455,7 @@ function CountlyBulkUser(conf) {
419455

420456
if (this.check_consent("views")) {
421457
var event = {
422-
"key": "[CLY]_view",
458+
"key": cc.internalEventKeyEnums.VIEW,
423459
"dur": duration,
424460
"count": 1,
425461
"segmentation": {
@@ -474,7 +510,7 @@ function CountlyBulkUser(conf) {
474510
if (this.check_consent("events")) {
475511
var props = ["widget_id", "contactMe", "platform", "app_version", "rating", "email", "comment"];
476512
var event = {
477-
key: "[CLY]_star_rating",
513+
key: cc.internalEventKeyEnums.STAR_RATING,
478514
count: 1,
479515
segmentation: {}
480516
};

lib/countly-common.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,26 @@ var cc = {
2323
DEBUG: '[DEBUG] ',
2424
VERBOSE: '[VERBOSE] ',
2525
},
26+
/**
27+
* At the current moment there are following internal events and their respective required consent:
28+
[CLY]_nps - "feedback" consent
29+
[CLY]_survey - "feedback" consent
30+
[CLY]_star_rating - "star_rating" consent
31+
[CLY]_view - "view" consent
32+
[CLY]_orientation - "users" consent
33+
[CLY]_push_action - "push" consent
34+
[CLY]_action - "clicks" or "scroll" consent
35+
*/
36+
internalEventKeyEnums: {
37+
NPS: '[CLY]_nps',
38+
SURVEY: '[CLY]_survey',
39+
STAR_RATING: '[CLY]_star_rating',
40+
VIEW: '[CLY]_view',
41+
ORIENTATION: '[CLY]_orientation',
42+
PUSH_ACTION: '[CLY]_push_action',
43+
ACTION: '[CLY]_action'
44+
},
45+
2646
/**
2747
* Get current timestamp
2848
* @returns {number} unix timestamp in seconds

lib/countly.js

Lines changed: 107 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -220,40 +220,72 @@ Countly.Bulk = Bulk;
220220
*
221221
* Resets Countly to its initial state (used mainly to wipe the queues in memory).
222222
* Calling this will result in a loss of data
223+
* @param {boolean} preventRequestProcessing - if true request queues wont be processed, for testing purposes
223224
*/
224-
Countly.halt = function name() {
225+
Countly.halt = function(preventRequestProcessing) {
225226
cc.log(cc.logLevelEnums.WARNING, "halt, Resetting Countly");
226227
inited = false;
227228
sessionStarted = false;
228-
beatInterval = 500,
229-
queueSize = 1000,
230-
requestQueue = [],
231-
eventQueue = [],
232-
remoteConfigs = {},
233-
crashLogs = [],
234-
timedEvents = {},
235-
crashSegments = null,
236-
autoExtend = true,
237-
storedDuration = 0,
238-
lastView = null,
239-
lastViewTime = 0,
240-
lastMsTs = 0,
241-
lastViewStoredDuration = 0,
242-
failTimeout = 0,
243-
failTimeoutAmount = 60,
244-
sessionUpdate = 60,
245-
maxEventBatch = 100,
246-
readyToProcess = true,
247-
trackTime = true,
248-
metrics = {},
249-
lastParams = {},
250-
maxKeyLength = 128,
251-
maxValueSize = 256,
252-
maxSegmentationValues = 30,
253-
maxBreadcrumbCount = 100,
254-
maxStackTraceLinesPerThread = 30,
255-
maxStackTraceLineLength = 200,
229+
beatInterval = 500;
230+
queueSize = 1000;
231+
requestQueue = [];
232+
eventQueue = [];
233+
remoteConfigs = {};
234+
crashLogs = [];
235+
timedEvents = {};
236+
crashSegments = null;
237+
autoExtend = true;
238+
storedDuration = 0;
239+
lastView = null;
240+
lastViewTime = 0;
241+
lastMsTs = 0;
242+
lastViewStoredDuration = 0;
243+
failTimeout = 0;
244+
failTimeoutAmount = 60;
245+
sessionUpdate = 60;
246+
maxEventBatch = 100;
247+
readyToProcess = !preventRequestProcessing;
248+
trackTime = true;
249+
metrics = {};
250+
lastParams = {};
251+
maxKeyLength = 128;
252+
maxValueSize = 256;
253+
maxSegmentationValues = 30;
254+
maxBreadcrumbCount = 100;
255+
maxStackTraceLinesPerThread = 30;
256+
maxStackTraceLineLength = 200;
256257
__data = {};
258+
259+
//cc DEBUG
260+
cc.debug = false;
261+
cc.debugBulk = false;
262+
cc.debugBulkUser = false;
263+
264+
//CONSENTS
265+
consents = {};
266+
for (var a = 0; a < Countly.features.length; a++) {
267+
consents[Countly.features[a]] = {};
268+
}
269+
270+
//device_id
271+
Countly.device_id = undefined;
272+
Countly.remote_config = undefined;
273+
Countly.require_consent = false;
274+
Countly.debug = undefined;
275+
Countly.app_key = undefined;
276+
Countly.url = undefined;
277+
Countly.app_version = undefined;
278+
Countly.country_code = undefined;
279+
Countly.city = undefined;
280+
Countly.ip_address = undefined;
281+
Countly.force_post = undefined;
282+
Countly.storage_path = undefined;
283+
Countly.require_consent = undefined;
284+
Countly.http_options = undefined;
285+
286+
asyncWriteLock = false;
287+
asyncWriteQueue = [];
288+
257289
};
258290

259291
/**
@@ -304,10 +336,16 @@ Countly.Bulk = Bulk;
304336
Countly.check_consent = function(feature) {
305337
if (!Countly.require_consent) {
306338
//we don't need to have specific consents
339+
cc.log(cc.logLevelEnums.INFO, "check_consent, Require consent is off. Giving consent for : [ " + feature + " ] feature.");
340+
return true;
341+
}
342+
if (consents[feature] && consents[feature].optin) {
343+
cc.log(cc.logLevelEnums.INFO, "check_consent, Giving consent for : [ " + feature + " ] feature.");
307344
return true;
308345
}
309-
if (consents[feature]) {
310-
return (consents[feature] && consents[feature].optin) ? true : false;
346+
if (consents[feature] && !consents[feature].optin) {
347+
cc.log(cc.logLevelEnums.ERROR, "check_consent, User is not optin. Consent refused for : [ " + feature + " ] feature.");
348+
return false;
311349
}
312350
else {
313351
cc.log(cc.logLevelEnums.ERROR, "check_consent, No feature available for " + feature);
@@ -427,7 +465,7 @@ Countly.Bulk = Bulk;
427465
updateConsent();
428466
}
429467
}
430-
cc.log("Consent removal triggered.");
468+
cc.log(cc.logLevelEnums.DEBUG, "remove_consent, Consent removal triggered.");
431469

432470
}
433471
else {
@@ -453,7 +491,7 @@ Countly.Bulk = Bulk;
453491
}
454492
}
455493
toRequestQueue({consent: JSON.stringify(consentMessage)});
456-
cc.log("Consent update request has been sent to the queue.");
494+
cc.log(cc.logLevelEnums.DEBUG, "Consent update request has been sent to the queue.");
457495
}, 1000);
458496
};
459497

@@ -573,11 +611,41 @@ Countly.Bulk = Bulk;
573611
* @param {Object=} event.segmentation - object with segments key /values
574612
**/
575613
Countly.add_event = function(event) {
576-
if (Countly.check_consent("events")) {
614+
cc.log('Trying to add the event: [ ' + event.key + ' ]');
615+
//initially no consent is given
616+
var respectiveConsent = false;
617+
//to match the internal events and their respective required consents. Sets respectiveConsent to true if the consent is given
618+
switch (event.key) {
619+
case cc.internalEventKeyEnums.NPS:
620+
respectiveConsent = Countly.check_consent('feedback');
621+
break;
622+
case cc.internalEventKeyEnums.SURVEY:
623+
respectiveConsent = Countly.check_consent('feedback');
624+
break;
625+
case cc.internalEventKeyEnums.STAR_RATING:
626+
respectiveConsent = Countly.check_consent('star-rating');
627+
break;
628+
case cc.internalEventKeyEnums.VIEW:
629+
respectiveConsent = Countly.check_consent('views');
630+
break;
631+
case cc.internalEventKeyEnums.ORIENTATION:
632+
respectiveConsent = Countly.check_consent('users');
633+
break;
634+
case cc.internalEventKeyEnums.PUSH_ACTION:
635+
respectiveConsent = Countly.check_consent('push');
636+
break;
637+
case cc.internalEventKeyEnums.ACTION:
638+
respectiveConsent = Countly.check_consent('clicks') || Countly.check_consent('scroll');
639+
break;
640+
default:
641+
respectiveConsent = Countly.check_consent('events');
642+
643+
}
644+
//if consent is given adds event to the queue
645+
if (respectiveConsent) {
577646
add_cly_events(event);
578647
}
579648
};
580-
581649
/**
582650
* Add events to event queue
583651
* @memberof Countly._internals
@@ -894,7 +962,7 @@ Countly.Bulk = Bulk;
894962
if (Countly.check_consent("events")) {
895963
var props = ["widget_id", "contactMe", "platform", "app_version", "rating", "email", "comment"];
896964
var event = {
897-
key: "[CLY]_star_rating",
965+
key: cc.internalEventKeyEnums.STAR_RATING,
898966
count: 1,
899967
segmentation: {}
900968
};
@@ -1113,7 +1181,7 @@ Countly.Bulk = Bulk;
11131181
//track pageview
11141182
if (Countly.check_consent("views")) {
11151183
add_cly_events({
1116-
"key": "[CLY]_view",
1184+
"key": cc.internalEventKeyEnums.VIEW,
11171185
"segmentation": segments
11181186
});
11191187
}
@@ -1229,7 +1297,7 @@ Countly.Bulk = Bulk;
12291297
//track pageview
12301298
if (Countly.check_consent("views")) {
12311299
add_cly_events({
1232-
"key": "[CLY]_view",
1300+
"key": cc.internalEventKeyEnums.VIEW,
12331301
"dur": cc.getTimestamp() - lastViewTime,
12341302
"segmentation": segments
12351303
});
@@ -1328,7 +1396,7 @@ Countly.Bulk = Bulk;
13281396
if (err) {
13291397
requestQueue.unshift(res);
13301398
failTimeout = cc.getTimestamp() + failTimeoutAmount;
1331-
cc.log("Encountered a problem while making the request.");
1399+
cc.log(cc.logLevelEnums.ERROR, "makeRequest, Encountered a problem while making the request.");
13321400
}
13331401
storeSet("cly_queue", requestQueue);
13341402
readyToProcess = true;

0 commit comments

Comments
 (0)