Skip to content

Commit 5fae4f4

Browse files
committed
Merge branch 'master' into release.24.10
# Conflicts: # CHANGELOG.md # plugins/crashes/api/api.js # plugins/crashes/tests.js
2 parents 2313d02 + 35146e8 commit 5fae4f4

File tree

7 files changed

+104
-11
lines changed

7 files changed

+104
-11
lines changed

CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## Version 24.10.2
2+
Fixes:
3+
- [core] Fixed bug where changing passwords results in the loss of the "Global Admin" role
4+
- [core] Fixed bug where exporting incoming data logs could result in "Incorrect parameter \"data\" error
5+
- [crash] Fixed bug in crash ingestion for scenarios where the "app version" is not a string.
6+
- [script] Fixing bug with "delete_old_members" script that led to malformed requests
7+
8+
Enterprise fixes:
9+
- [nps] Fixed bug that showed the wrong nps preview title
10+
111
## Version 24.10.1
212
Fixes:
313
- [core] Replaced "Users" with "Sessions" label on technology home widgets
@@ -61,6 +71,7 @@ Enterprise Features:
6171

6272
## Version 24.05.15
6373
Enterprise fixes:
74+
- [ab-testing] Fixed JSON.parse issue preventing creation of AB tests
6475
- [nps] Fixed UI issues in the widget editor related to the "user consent" section
6576
- [ratings] Fixed rendering issue for escaped values
6677

bin/scripts/member-managament/delete_old_members.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Promise.all([pluginManager.dbConnection("countly")]).spread(function(countlyDb)
4444
Url: SERVER_URL + "/i/users/delete",
4545
body: {
4646
api_key: API_KEY,
47-
args: JSON.stringify({user_ids: [(data._id + "")]})
47+
args: {user_ids: [data._id + ""]}
4848
}
4949
}, function(data) {
5050
if (data.err) {
@@ -99,8 +99,7 @@ function sendRequest(params, callback) {
9999
const options = {
100100
uri: url.href,
101101
method: params.requestType,
102-
json: true,
103-
body: body,
102+
json: body,
104103
strictSSL: false
105104
};
106105

frontend/express/public/core/user-management/javascripts/countly.views.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -949,8 +949,20 @@
949949
watch: {
950950
'groups': function() {
951951
if (this.groups.length > 0) {
952-
// Remove global admin role if user is assigned to any group
953-
this.$refs.userDrawer.editedObject.global_admin = false;
952+
// Remove global admin role if the assigned groups does not have global admin access
953+
var groupHasGlobalAdmin = false;
954+
955+
this.groups.forEach(function(grpId) {
956+
var group = groupsModel.data().find(function(grp) {
957+
return grpId === grp._id;
958+
});
959+
960+
if (group && group.global_admin === true) {
961+
groupHasGlobalAdmin = true;
962+
}
963+
});
964+
965+
this.$refs.userDrawer.editedObject.global_admin = groupHasGlobalAdmin;
954966
}
955967

956968
if (this.groups.length === 0) {
@@ -1152,4 +1164,4 @@
11521164
countlyVue.container.registerData("user-management/edit-user-drawer", {
11531165
component: Drawer
11541166
});
1155-
})();
1167+
})();

plugins/crashes/api/api.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,12 @@ plugins.setConfigs("crashes", {
464464
}
465465
updateUser.hadAnyNonfatalCrash = report.ts;
466466
}
467-
let updateData = { $inc: {} };
467+
468+
if ('app_version' in report && typeof report.app_version !== 'string') {
469+
report.app_version += '';
470+
}
471+
let updateData = {$inc: {}};
472+
468473
updateData.$inc["data.crashes"] = 1;
469474
if (Object.keys(updateUser).length) {
470475
updateData.$set = updateUser;

plugins/crashes/tests.js

+29
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,35 @@ describe('Testing Crashes', function() {
31433143
.get('/i/crashes/delete?args=' + JSON.stringify({ crash_id: crashGroup._id }) + '&app_id=' + APP_ID + '&api_key=' + API_KEY_ADMIN);
31443144
});
31453145
});
3146+
3147+
describe('Crash app version', async() => {
3148+
it('should process crash app version as string', async() => {
3149+
const crashData = {
3150+
"_error": "error",
3151+
"_app_version": 123, // app version is number
3152+
"_os": "android",
3153+
};
3154+
3155+
await request.get('/i')
3156+
.query({ app_key: APP_KEY, device_id: DEVICE_ID, crash: JSON.stringify(crashData) })
3157+
.expect(200);
3158+
3159+
const crashGroupQuery = JSON.stringify({
3160+
latest_version: { $in: [`${crashData._app_version}`] },
3161+
});
3162+
let crashGroupResponse = await request
3163+
.get('/o')
3164+
.query({ method: 'crashes', api_key: API_KEY_ADMIN, app_id: APP_ID, query: crashGroupQuery });
3165+
const crashGroup = crashGroupResponse.body.aaData[0];
3166+
crashGroupResponse = await request
3167+
.get(`/o?`)
3168+
.query({ method: 'crashes', api_key: API_KEY_ADMIN, app_id: APP_ID, group: crashGroup._id });
3169+
3170+
const crash = crashGroupResponse.body.data[0];
3171+
3172+
crash.app_version.should.equal(`${crashData._app_version}`);
3173+
});
3174+
});
31463175

31473176
describe('Reset app', function() {
31483177
it('should reset data', function(done) {

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

+40-3
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,44 @@
130130
formatExportFunction: function() {
131131
var tableData = this.logsData;
132132
var table = [];
133+
var sanitizeQueryData = function(data) {
134+
try {
135+
// If data is already a string, parse it first
136+
let queryObject = typeof data === 'string' ? JSON.parse(data) : data;
137+
138+
// Handle nested JSON strings within the object
139+
Object.keys(queryObject).forEach(key => {
140+
if (typeof queryObject[key] === 'string') {
141+
// Try to parse if it looks like JSON
142+
if (queryObject[key].startsWith('{') || queryObject[key].startsWith('[')) {
143+
try {
144+
queryObject[key] = JSON.parse(queryObject[key]);
145+
if (typeof queryObject[key] === 'object' && queryObject[key] !== null) {
146+
queryObject[key] = sanitizeQueryData(queryObject[key]);
147+
}
148+
}
149+
catch (e) {
150+
// If parsing fails, keep decoded string
151+
}
152+
}
153+
queryObject[key] = countlyCommon.unescapeHtml(queryObject[key]);
154+
}
155+
else if (typeof queryObject[key] === 'object' && queryObject[key] !== null) {
156+
// Recursively handle nested objects
157+
Object.keys(queryObject[key]).forEach(nestedKey => {
158+
if (typeof queryObject[key][nestedKey] === 'string') {
159+
queryObject[key][nestedKey] = countlyCommon.unescapeHtml(queryObject[key][nestedKey]);
160+
}
161+
});
162+
}
163+
});
164+
return JSON.stringify(queryObject);
165+
}
166+
catch (err) {
167+
return data; // Return original data if processing fails
168+
}
169+
};
170+
133171
for (var i = 0; i < tableData.length; i++) {
134172
var item = {};
135173
item[CV.i18n('logger.requests').toUpperCase()] = countlyCommon.formatTimeAgoText(tableData[i].reqts).text;
@@ -152,16 +190,15 @@
152190
}
153191
if (tableData[i].q) {
154192
try {
155-
item[CV.i18n('logger.request-query').toUpperCase()] = JSON.stringify(tableData[i].q);
193+
item[CV.i18n('logger.request-query').toUpperCase()] = sanitizeQueryData(tableData[i].q);
156194
}
157195
catch (err) {
158196
item[CV.i18n('logger.request-header').toUpperCase()] = "-";
159197
}
160198
}
161199
if (tableData[i].h) {
162200
try {
163-
var stringifiedHeader = JSON.stringify(tableData[i].h);
164-
item["REQUEST HEADER"] = stringifiedHeader.replace(/&quot;/g, '"');
201+
item["REQUEST HEADER"] = sanitizeQueryData(tableData[i].h);
165202
}
166203
catch (err) {
167204
item["REQUEST HEADER"] = "-";

plugins/views/scripts/omitViewSegments.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function getAppList(options, callback) {
110110
if (app_list && app_list.length > 0) {
111111
var listed = [];
112112
for (var z = 0; z < app_list.length; z++) {
113-
listed.push(options.db.ObjectId(app_list[z]));
113+
listed.push(options.db.ObjectID(app_list[z]));
114114
}
115115
query = {_id: {$in: listed}};
116116
}

0 commit comments

Comments
 (0)