Skip to content

Commit

Permalink
Merge pull request #16 from Countly/set_id-addition
Browse files Browse the repository at this point in the history
Set id addition
  • Loading branch information
turtledreams authored Jun 12, 2024
2 parents 271f385 + f19851e commit cf5c572
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 43 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 24.4.1

* Added a new method `set_id(newDeviceId)` for managing device id changes according to the device ID Type.

## 24.4.0

! Minor breaking change ! For implementations using `salt` the browser compatability is tied to SubtleCrypto's `digest` method support
Expand Down
67 changes: 66 additions & 1 deletion cypress/e2e/device_id_change.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ describe("Device ID change tests ", ()=>{
});
});
});
it("Check init time temp mode with set_id", () => {
hp.haltAndClearStorage(() => {
initMain(true); // init in offline mode
testDeviceIdInReqs(() => {
Countly.set_id("new ID");
});
});
});

// ========================================
// default init configuration tests
Expand Down Expand Up @@ -209,4 +217,61 @@ describe("Device ID change tests ", ()=>{
});
});
});
});
});

describe("Set ID change tests ", () => {
it('set_id should be non merge as there was dev provided id', () => {
hp.haltAndClearStorage(() => {
Countly.init({
app_key: "YOUR_APP_KEY",
url: "https://your.domain.count.ly",
test_mode: true,
debug: true,
device_id: "old ID"
});
Countly.add_event(eventObj("1")); // record an event.
cy.wait(500); // wait for the request to be sent
cy.fetch_local_request_queue().then((eq) => {
expect(eq[0].device_id).to.equal("old ID");
Countly.set_id("new ID");
Countly.add_event(eventObj("2")); // record another event
cy.wait(500); // wait for the request to be sent
cy.fetch_local_request_queue().then((eq2) => {
expect(eq2.length).to.equal(3); // no merge request
expect(eq2[0].device_id).to.equal("old ID");
expect(eq2[0].events).to.contains('"key\":\"1\"');
expect(eq2[1].device_id).to.equal("new ID");
expect(eq2[1].begin_session).to.equal(1);
expect(eq2[2].device_id).to.equal("new ID");
expect(eq2[2].events).to.contains('"key\":\"2\"');
});
});
});
});
it('set_id should be merge as there was sdk generated id', () => {
hp.haltAndClearStorage(() => {
initMain(false); // init normally
Countly.add_event(eventObj("1")); // record an event.
cy.wait(500); // wait for the request to be sent
let generatedID;
cy.fetch_local_request_queue().then((eq) => {
cy.log(eq);
generatedID = eq[0].device_id; // get the new id from first item in the queue
Countly.set_id("new ID");
Countly.add_event(eventObj("2")); // record another event
cy.wait(500); // wait for the request to be sent
cy.fetch_local_request_queue().then((eq2) => {
cy.log(eq2);
expect(eq2.length).to.equal(3); // merge request
expect(eq2[0].device_id).to.equal(generatedID);
expect(eq2[0].events).to.contains('"key\":\"1\"');
expect(eq2[1].device_id).to.equal("new ID");
expect(eq2[1].old_device_id).to.equal(generatedID);
expect(eq2[2].device_id).to.equal("new ID");
expect(eq2[2].events).to.contains('"key\":\"2\"');
});
});
});
});

});
2 changes: 1 addition & 1 deletion modules/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ var healthCheckCounterEnum = Object.freeze({
errorMessage: "cly_hc_error_message",
});

var SDK_VERSION = "24.4.0";
var SDK_VERSION = "24.4.1";
var SDK_NAME = "javascript_native_web";

// Using this on document.referrer would return an array with 17 elements in it. The 12th element (array[11]) would be the path we are looking for. Others would be things like password and such (use https://regex101.com/ to check more)
Expand Down
98 changes: 58 additions & 40 deletions modules/CountlyClass.js
Original file line number Diff line number Diff line change
Expand Up @@ -984,17 +984,33 @@ class CountlyClass {
};

/**
* Change current user/device id
* Changes the current device ID according to the device ID type (the preffered method)
* @param {string} newId - new user/device ID to use. Must be a non-empty string value. Invalid values (like null, empty string or undefined) will be rejected
* */
this.set_id = function (newId) {
log(logLevelEnums.INFO, "set_id, Changing the device ID to:[" + newId + "]");
if (newId == null || newId === "") {
log(logLevelEnums.WARNING, "set_id, The provided device is not a valid ID");
return;
}
if (deviceIdType === DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED) {
/*change ID without merge as current ID is Dev supplied, so not first login*/
this.change_id(newId, false);
} else {
/*change ID with merge as current ID is not Dev supplied*/
this.change_id(newId, true);
}
}

/**
* Change current user/device id (use set_id instead if you are not sure about the merge operation)
* @param {string} newId - new user/device ID to use. Must be a non-empty string value. Invalid values (like null, empty string or undefined) will be rejected
* @param {boolean} merge - move data from old ID to new ID on server
* */
this.change_id = function (newId, merge) {
log(logLevelEnums.INFO, "change_id, Changing the ID");
if (merge) {
log(logLevelEnums.INFO, "change_id, Will merge the IDs");
}
log(logLevelEnums.INFO, "change_id, Changing the device ID to: [" + newId + "] with merge:[" + merge + "]");
if (!newId || typeof newId !== "string" || newId.length === 0) {
log(logLevelEnums.ERROR, "change_id, The provided ID: [" + newId + "] is not a valid ID");
log(logLevelEnums.WARNING, "change_id, The provided device ID is not a valid ID");
return;
}
if (offlineMode) {
Expand All @@ -1004,40 +1020,42 @@ class CountlyClass {
}
// eqeq is used here since we want to catch number to string checks too. type conversion might happen at a new init
// eslint-disable-next-line eqeqeq
if (this.device_id != newId) {
if (!merge) {
// process async queue before sending events
processAsyncQueue();
// empty event queue
sendEventsForced();
// end current session
this.end_session(null, true);
// clear timed events
timedEvents = {};
// clear all consents
this.remove_consent_internal(Countly.features, false);
}
var oldId = this.device_id;
this.device_id = newId;
self.device_id = this.device_id;
deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED;
setValueInStorage("cly_id", this.device_id);
setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED);
log(logLevelEnums.INFO, "change_id, Changing ID from:[" + oldId + "] to [" + newId + "]");
if (merge) {
// no consent check here since 21.11.0
toRequestQueue({ old_device_id: oldId });
}
else {
// start new session for new ID
this.begin_session(!autoExtend, true);
}
// if init time remote config was enabled with a callback function, remove currently stored remote configs and fetch remote config again
if (this.remote_config) {
remoteConfigs = {};
setValueInStorage("cly_remote_configs", remoteConfigs);
this.fetch_remote_config(this.remote_config);
}
if (this.device_id == newId) {
log(logLevelEnums.DEBUG, "change_id, Provided device ID is equal to the current device ID. Aborting.");
return;
}
if (!merge) {
// process async queue before sending events
processAsyncQueue();
// empty event queue
sendEventsForced();
// end current session
this.end_session(null, true);
// clear timed events
timedEvents = {};
// clear all consents
this.remove_consent_internal(Countly.features, false);
}
var oldId = this.device_id;
this.device_id = newId;
self.device_id = this.device_id;
deviceIdType = DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED;
setValueInStorage("cly_id", this.device_id);
setValueInStorage("cly_id_type", DeviceIdTypeInternalEnums.DEVELOPER_SUPPLIED);
log(logLevelEnums.INFO, "change_id, Changing ID from:[" + oldId + "] to [" + newId + "]");
if (merge) {
// no consent check here since 21.11.0
toRequestQueue({ old_device_id: oldId });
}
else {
// start new session for new ID TODO: check this when no session tracking is enabled
this.begin_session(!autoExtend, true);
}
// if init time remote config was enabled with a callback function, remove currently stored remote configs and fetch remote config again
if (this.remote_config) {
remoteConfigs = {};
setValueInStorage("cly_remote_configs", remoteConfigs);
this.fetch_remote_config(this.remote_config);
}
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "countly-sdk-js",
"version": "24.4.0",
"version": "24.4.1",
"description": "Countly JavaScript SDK",
"type": "module",
"main": "Countly.js",
Expand Down

0 comments on commit cf5c572

Please sign in to comment.