Skip to content

Commit 0e23180

Browse files
authored
Merge pull request #41 from Countly/user-picture-upload
UP picture upload
2 parents 0c989de + 2feef5a commit 0e23180

File tree

8 files changed

+369
-18
lines changed

8 files changed

+369
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
## X.X.X
22

33
* Mitigated an issue where manual feedback reporting could have failed
4+
* Mitigated a possible issue with request timeouts in IE11
5+
* Non window contexts also now uses POST requests by default
6+
* Added a new method `uploadUserProfilePicture` for uploading user profile images to server
47

58
## 25.4.1
69

@@ -35,7 +38,7 @@
3538

3639
## 24.11.4
3740

38-
* Mitigated an issue where `content` and `feedback` interfaces would not work with async multi instances.
41+
* Mitigated an issue where `content` and `feedback` interfaces would not work with async multi instances.
3942

4043
## 24.11.3
4144

cypress/e2e/namespace.cy.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* eslint-disable require-jsdoc */
2+
var Countly = require("../../Countly.js");
3+
var hp = require("../support/helper");
4+
5+
const c1 = ['sessions', 'events', 'views', 'users', 'scrolls', 'clicks'];
6+
const c2 = ['events', 'users', 'location'];
7+
8+
describe("-", () => {
9+
it("-", () => {
10+
hp.haltAndClearStorage(() => {
11+
Countly.init({
12+
app_key: "YOUR_APP_KEY1",
13+
url: "https://your.domain.count.ly",
14+
namespace: "namespace1",
15+
clear_stored_id: true,
16+
device_id: "test-device-id1",
17+
require_consent: true,
18+
enable_orientation_tracking: false,
19+
});
20+
Countly.add_consent(c1);
21+
Countly.user_details({organization: "Test Organization1", custom: {"Test User1": "Test User1"}});
22+
Countly.track_sessions();
23+
Countly.track_pageview();
24+
Countly.track_clicks();
25+
Countly.track_scrolls();
26+
Countly.add_event({
27+
key: "test_event1",
28+
count: 1,
29+
segmentation: {test: "test1"},
30+
});
31+
32+
Countly.q.push(["init", {
33+
app_key: "YOUR_APP_KEY2", //must have different APP key
34+
url: "https://your.domain.count.ly",
35+
namespace: "namespace2",
36+
clear_stored_id: true,
37+
device_id: "test-device-id2",
38+
require_consent: true,
39+
enable_orientation_tracking: false,
40+
}])
41+
Countly.q.push(["YOUR_APP_KEY2", "add_consent", c2]);
42+
Countly.q.push(["YOUR_APP_KEY2", "user_details", {organization: "Test Organization2", custom: {"Test User2": "Test User2"}}]);
43+
Countly.q.push(["YOUR_APP_KEY2", "track_sessions"]);
44+
Countly.q.push(["YOUR_APP_KEY2", "track_pageview", undefined, undefined, {test: "test2"}]);
45+
Countly.q.push(["YOUR_APP_KEY2", "track_clicks"]);
46+
Countly.q.push(["YOUR_APP_KEY2", "track_scrolls"]);
47+
Countly.q.push(["YOUR_APP_KEY2", "add_event", {
48+
key: "test_event2",
49+
count: 1,
50+
segmentation: {test: "test2"},
51+
}]);
52+
53+
cy.wait(1000).then(() => {
54+
var queues = Countly._internals.getLocalQueues();
55+
var requests = Countly._internals.testingGetRequests();
56+
cy.log(queues);
57+
cy.log(requests);
58+
});
59+
});
60+
});
61+
});

cypress/e2e/salt.cy.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@ describe("Salt Tests", () => {
6262
hp.check_commons(paramsObject);
6363
expect(paramsObject.checksum256).to.be.ok;
6464
expect(paramsObject.checksum256.length).to.equal(64);
65+
expect(paramsObject.checksum256).to.match(/^[A-F0-9]{64}$/);
6566
// TODO: directly check the checksum with the node crypto api. Will need some extra decoding logic
6667
}
6768
});
6869
});
6970
});
7071
});
7172
it('Node and Web Crypto comparison', () => {
72-
const hash = sha256("text" + salt); // node crypto api
73+
const hash = sha256("text" + salt).toUpperCase(); // node crypto api
7374
Utils.calculateChecksum("text", salt).then((hash2) => { // SDK uses web crypto api
7475
expect(hash2).to.equal(hash);
7576
});
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* eslint-disable require-jsdoc */
2+
var Countly = require("../../Countly.js");
3+
var hp = require("../support/helper");
4+
5+
function initMain() {
6+
Countly.init({
7+
app_key: "YOUR_APP_KEY",
8+
url: "https://your.domain.count.ly",
9+
test_mode: true,
10+
test_mode_eq: true,
11+
debug: true
12+
});
13+
}
14+
15+
describe("Upload user profile picture", () => {
16+
it("queues an image upload request when given a File-like object (Blob)", () => {
17+
hp.haltAndClearStorage(() => {
18+
initMain();
19+
20+
// red dot PNG
21+
const base64Png = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=";
22+
const binary = Cypress.Blob.base64StringToBlob(base64Png, 'image/png');
23+
binary.name = "avatar.png";
24+
Countly.uploadUserProfilePicture(binary);
25+
26+
cy.wait(500).then(() => {
27+
cy.getLocalStorage("YOUR_APP_KEY/cly_queue").then((val) => {
28+
expect(val).to.be.ok;
29+
const queue = JSON.parse(val);
30+
expect(queue.length).to.be.greaterThan(0);
31+
32+
const imgReq = queue.find(r => r.__imageUpload === true || r.imageData);
33+
expect(imgReq).to.be.ok;
34+
expect(imgReq.imageName).to.be.oneOf(["avatar.png", "avatar"]);
35+
expect(imgReq.imageType).to.equal('image/png');
36+
expect(imgReq.imageData).to.be.a('string').and.to.have.length.greaterThan(0);
37+
38+
expect(imgReq.user_details).to.be.a('string');
39+
const ud = JSON.parse(imgReq.user_details);
40+
expect(ud).to.be.an('object');
41+
});
42+
});
43+
});
44+
});
45+
46+
it("rejects non-image files and does not queue requests", () => {
47+
hp.haltAndClearStorage(() => {
48+
initMain();
49+
50+
const txtBlob = new Blob(["hello world"], { type: 'text/plain' });
51+
txtBlob.name = "test.txt";
52+
Countly.uploadUserProfilePicture(txtBlob);
53+
54+
cy.wait(300).then(() => {
55+
cy.getLocalStorage("YOUR_APP_KEY/cly_queue").then((val) => {
56+
if (!val) {
57+
expect(val).to.be.not.ok;
58+
return;
59+
}
60+
const queue = JSON.parse(val || '[]');
61+
const imgReq = queue.find(r => r.__imageUpload === true || r.imageData);
62+
expect(imgReq).to.not.exist;
63+
});
64+
});
65+
});
66+
});
67+
});

examples/example_async.html

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
if(Countly.app_key === "YOUR_APP_KEY" || Countly.url === "https://your.server.ly"){
2020
console.warn("Please do not use default set of app key and server url")
2121
}
22-
Countly.debug = true;
2322

2423
//start pushing function calls to queue
2524
//track sessions automatically
@@ -39,7 +38,8 @@
3938
cly.src = '../Countly.js';
4039
cly.onload = function () {
4140
console.log("Countly script loaded");
42-
Countly.init() };
41+
Countly.init()
42+
};
4343
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);
4444
})();
4545
//send event on button click
@@ -51,6 +51,16 @@
5151
}
5252
}]);
5353
}
54+
55+
function uploadProfilePicture() {
56+
var fileInput = document.getElementById("profilePicInput");
57+
var file = fileInput.files[0];
58+
if (!file) {
59+
alert("Please select an image file.");
60+
return;
61+
}
62+
Countly.q.push(["uploadUserProfilePicture", file]);
63+
}
5464
</script>
5565
</head>
5666

@@ -64,7 +74,12 @@ <h1>Async Countly Implementation</h1>
6474
<center>
6575
<img src="./images/team_countly.jpg" id="wallpaper" />
6676
<br />
67-
<input type="button" id="testButton" onclick="clickEvent()" value="Test Button">
77+
<input type="button" id="testButton" onclick="clickEvent()" value="Test Button">
78+
<br /><br />
79+
<input type="file" id="profilePicInput" accept="image/*">
80+
<br /><br />
81+
<br />
82+
<input type="button" onclick="uploadProfilePicture()" value="Upload Profile Picture">
6883
<p><a href='https://countly.com/'>Countly</a></p>
6984
</center>
7085
</body>

examples/example_sync.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@
3535
}
3636
});
3737
});
38+
39+
document.getElementById("uploadBtn").addEventListener("click", function() {
40+
var fileInput = document.getElementById("profilePicInput");
41+
var file = fileInput.files[0];
42+
if (!file) {
43+
alert("Please select an image file.");
44+
return;
45+
}
46+
Countly.uploadUserProfilePicture(file);
47+
});
3848
</script>
3949
</head>
4050

@@ -49,6 +59,10 @@ <h1>Sync Countly Implementation</h1>
4959
<img src="./images/team_countly.jpg" id="wallpaper" />
5060
<br />
5161
<input type="button" id="testButton" onclick="clickEvent()" value="Test Button">
62+
<br /><br />
63+
<input type="file" id="profilePicInput" accept="image/*">
64+
<br /><br />
65+
<input type="button" id="uploadBtn" value="Upload Profile Picture">
5266
<p><a href='https://countly.com/'>Countly</a></p>
5367
</center>
5468
</body>

0 commit comments

Comments
 (0)