Skip to content

Commit 124d282

Browse files
committed
Merge branch 'QT-227' of github.com:Countly/countly-server into QT-227
2 parents 6e4cb09 + 82e02d2 commit 124d282

File tree

137 files changed

+4794
-3501
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+4794
-3501
lines changed

CHANGELOG.md

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
## Version 24.05.14
2+
Fixes:
3+
- [code] Added better handling for countly servers while deployed using subdirectory
4+
- [data-manager] Added missing "Create" button for event groups
5+
- [data-manager] Fixes for auto toggling data masking setting on redaction change
6+
- [populator] Fixed issues in case of wrongly structured data
7+
- [push] token shouldn't be revoked if it's already in db
8+
- [server-stats] Fixed a data point calculation bug
9+
10+
Enterprise fixes:
11+
- [push_approver] Fixed issue with the plugin not handling being "soft disabled"
12+
- [surveys] fixed a bug with the Survey widget where the "submit" button could become non interactable
13+
- [surveys] fixed issues with dashboard editor in relation to the "terms and conditions"
14+
- [surveys] fixed issues with previewing, creating and editing nps widgets
15+
16+
## Version 24.05.13
17+
Fixes:
18+
- [alerts] Fixed bugs related to NPS alerts
19+
- [crash] Reworked symbol files upload to support larger symbol files
20+
- [push] Fixed bug that would surface when sending Array or Object related payload
21+
22+
Enterprise fixes:
23+
- [ab-testing] Slight improvements to the UI and UX
24+
- [remote-config] Slight improvements to the UI and UX
25+
26+
Enterprise Features:
27+
- [ab-testing] Improved UI for selecting AB test expiration
28+
29+
## Version 24.05.12
30+
Fixes:
31+
- [dashboards] Fixes for dashboards grid
32+
- [dasboards] UI fix for dashboard widget action menu
33+
- [push] Refactored fcm API related code
34+
- [reports] Use config for encryption key in reports
35+
36+
Enterprise fixes:
37+
- [retention] Fixes for byval retention query calculation
38+
139
## Version 24.05.11
240
Fixes:
341
- [cache] Use a cursor without timeout
@@ -9,7 +47,7 @@ Fixes:
947
- [logs] Show collected problems on logger
1048

1149
Enterprise fixes:
12-
- [data-manager] Fixes n UI to allow events starting with "/"
50+
- [data-manager] Fixes in UI to allow events starting with "/"
1351
- [flows] Fixes for flows step generation
1452
- [surveys] Other is not allowed as a valid answer for required questions
1553

Gruntfile.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ module.exports = function(grunt) {
241241
'frontend/express/public/javascripts/dom/drop/drop-theme-countly.min.css',
242242
'frontend/express/public/javascripts/utils/tooltipster/tooltipster.bundle.min.css',
243243
'frontend/express/public/stylesheets/bulma/bulma-custom.css',
244-
'frontend/express/public/stylesheets/styles/manifest.css',
244+
'frontend/express/public/stylesheets/styles/manifest2.css',
245245
'frontend/express/public/stylesheets/vue/element-tiptap.css',
246246
]
247247
}
@@ -324,7 +324,25 @@ module.exports = function(grunt) {
324324

325325
grunt.registerTask('default', ['mochaTest']);
326326

327-
grunt.registerTask('dist', ['sass', 'concat', 'uglify', 'cssmin']);
327+
grunt.registerTask('replace-paths', 'Replace image paths in prod CSS files', function() {
328+
var cssFiles = [
329+
{
330+
filepath: 'frontend/express/public/stylesheets/styles/manifest.css',
331+
lookup: '../../images',
332+
replacement: '../images',
333+
newPath: 'frontend/express/public/stylesheets/styles/manifest2.css'
334+
}
335+
];
336+
337+
cssFiles.forEach(function(file) {
338+
var content = grunt.file.read(file.filepath);
339+
var newContent = content.replace(/\.\.\/\.\.\/images/g, file.replacement);
340+
grunt.file.write(file.newPath, newContent);
341+
grunt.log.writeln('Processed file: ' + file.filepath);
342+
});
343+
});
344+
345+
grunt.registerTask('dist', ['sass', 'concat', 'uglify', 'replace-paths', 'cssmin']);
328346

329347
grunt.registerTask('plugins', 'Minify plugin JS / CSS files and copy images', function() {
330348
var js = [], css = [], img = [], fs = require('fs'), path = require('path');

api/api.js

+13-5
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,18 @@ plugins.connectToAllDatabases().then(function() {
370370
}
371371

372372
const form = new formidable.IncomingForm(formidableOptions);
373-
req.body = '';
374-
req.on('data', (data) => {
375-
req.body += data;
376-
});
373+
if (/crash_symbols\/(add_symbol|upload_symbol)/.test(req.url)) {
374+
req.body = [];
375+
req.on('data', (data) => {
376+
req.body.push(data);
377+
});
378+
}
379+
else {
380+
req.body = '';
381+
req.on('data', (data) => {
382+
req.body += data;
383+
});
384+
}
377385

378386
let multiFormData = false;
379387
// Check if we have 'multipart/form-data'
@@ -432,4 +440,4 @@ plugins.connectToAllDatabases().then(function() {
432440

433441
plugins.loadConfigs(common.db);
434442
}
435-
});
443+
});

api/config.sample.js

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ var countlyConfig = {
9999
* @property {string} algorithm - name of the algorithm to use for encryption. The algorithm is dependent on OpenSSL, examples are 'aes192', etc. On recent OpenSSL releases, openssl list-cipher-algorithms will display the available cipher algorithms. Default value is aes-256-cbc
100100
* @property {string} input_encoding - how encryption input is encoded. Used as output for decrypting. Default utf-8.
101101
* @property {string} output_encoding - how encryption output is encoded. Used as input for decrypting. Default hex.
102+
* @property {string} reports_key - key used for encryption of reports links
102103
*/
103104
encryption: {},
104105

api/parts/data/batcher.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ class WriteBatcher {
232232
updateOne: {
233233
filter: {_id: this.data[db][collection][key].id},
234234
update: this.data[db][collection][key].value,
235-
upsert: true
235+
upsert: this.data[db][collection][key].upsert
236236
}
237237
});
238238
}
@@ -340,18 +340,25 @@ class WriteBatcher {
340340
* @param {string} id - id of the document
341341
* @param {object} operation - operation
342342
* @param {string} db - name of the database for which to write data
343+
* @param {object=} options - options for operation ((upsert: false) - if you don't want to upsert document)
343344
*/
344-
add(collection, id, operation, db = "countly") {
345+
add(collection, id, operation, db = "countly", options) {
345346
if (!this.shared || cluster.isMaster) {
346347
if (!this.data[db][collection]) {
347348
this.data[db][collection] = {};
348349
}
349350
if (!this.data[db][collection][id]) {
350-
this.data[db][collection][id] = {id: id, value: operation};
351+
this.data[db][collection][id] = {id: id, value: operation, upsert: true};
352+
if (options && options.upsert === false) {
353+
this.data[db][collection][id].upsert = false;
354+
}
351355
batcherStats.update_queued++;
352356
}
353357
else {
354358
this.data[db][collection][id].value = common.mergeQuery(this.data[db][collection][id].value, operation);
359+
if (options && options.upsert === false) {
360+
this.data[db][collection][id].upsert = this.data[db][collection][id].upsert || false;
361+
}
355362
}
356363
if (!this.process) {
357364
this.flush(db, collection);

api/parts/data/cache.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ class StreamedCollection {
971971
let [col, last] = await createCollection(this.db, this.name, 1e7);
972972

973973
this.col = col;
974-
this.stream = col.find({_id: {$gt: last}}, {tailable: true, awaitData: true, noCursorTimeout: true, numberOfRetries: -1}).stream();
974+
this.stream = col.find({_id: {$gt: last}}, {tailable: true, awaitData: true, numberOfRetries: -1}).stream();
975975

976976
this.stream.on('data', doc => {
977977
if (this.inserts.indexOf(doc._id.toString()) !== -1) {

api/parts/data/fetch.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,7 @@ function fetchTimeObj(collection, params, isCustomEvent, options, callback) {
16141614
options = {};
16151615
}
16161616

1617-
if (typeof options === "undefined") {
1617+
if (!options) {
16181618
options = {};
16191619
}
16201620

@@ -1704,7 +1704,7 @@ function fetchTimeObj(collection, params, isCustomEvent, options, callback) {
17041704

17051705
var zeroDocs = [zeroIdToFetch];
17061706
var monthDocs = [monthIdToFetch];
1707-
if (!(options && options.dontBreak)) {
1707+
if (!options.dontBreak) {
17081708
for (let i = 0; i < common.base64.length; i++) {
17091709
zeroDocs.push(zeroIdToFetch + "_" + common.base64[i]);
17101710
monthDocs.push(monthIdToFetch + "_" + common.base64[i]);

api/parts/jobs/job.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1068,9 +1068,16 @@ class IPCFaçadeJob extends ResourcefulJob {
10681068
this.ipcChannel.remove();
10691069
}, (error) => {
10701070
this.ipcChannel.remove();
1071-
log.e('[%s] Error in IPCFaçadeJob %s: %j / %j', this.job.channel, this.resourceFaçade._id, error, error.stack);
1071+
if (error) {
1072+
log.e('[%s] Error in IPCFaçadeJob %s: %j / %j', this.job.channel, this.resourceFaçade._id, error, error.stack);
1073+
}
1074+
else {
1075+
log.e('[%s] Error in IPCFaçadeJob %s: Unknown error', this.job.channel, this.resourceFaçade._id);
1076+
}
10721077
this.job._finish(error || 'Aborted').catch(()=>{});
1073-
throw error;
1078+
if (error) {
1079+
throw error;
1080+
}
10741081
});
10751082
}
10761083

api/parts/mgmt/apps.js

+1
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ appsApi.updateAppPlugins = function(params) {
613613
* @returns {boolean} true if operation successful
614614
**/
615615
appsApi.deleteApp = function(params) {
616+
params = params || {};
616617
var argProps = {
617618
'app_id': {
618619
'required': true,

api/parts/mgmt/cms.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,21 @@ function syncCMSDataToDB(params) {
157157
}
158158

159159
cmsApi.saveEntries = function(params) {
160+
161+
var entries = [];
162+
try {
163+
entries = JSON.parse(params.qstring.entries);
164+
}
165+
catch (ex) {
166+
log.e(params.qstring.entries);
167+
common.returnMessage(params, 400, 'Invalid entries parameter');
168+
return;
169+
}
170+
160171
transformAndStoreData(
161172
Object.assign({dataTransformed: true}, params),
162173
null,
163-
JSON.parse(params.qstring.entries),
174+
entries,
164175
function(err1) {
165176
if (err1) {
166177
log.e('An error occured while storing entries in DB: ' + err1);

api/parts/mgmt/mail.js

+6
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ mail.sendToNewMember = function(member, memberPassword) {
186186
mail.sendToNewMemberLink = function(member, prid) {
187187
member.lang = member.lang || "en";
188188
mail.lookup(function(err, host) {
189+
if (config.path) {
190+
host = host + config.path;
191+
}
189192
localize.getProperties(member.lang, function(err2, properties) {
190193
var message = localize.format(properties["mail.new-member-prid"], mail.escapedHTMLString(mail.getUserFirstName(member)), host, mail.escapedHTMLString(member.username), prid);
191194
mail.sendMessage(member.email, properties["mail.new-member-subject"], message);
@@ -217,6 +220,9 @@ mail.sendToUpdatedMember = function(member, memberPassword) {
217220
mail.sendPasswordResetInfo = function(member, prid) {
218221
member.lang = member.lang || "en";
219222
mail.lookup(function(err, host) {
223+
if (config.path) {
224+
host = host + config.path;
225+
}
220226
localize.getProperties(member.lang, function(err2, properties) {
221227
var message = localize.format(properties["mail.password-reset"], mail.escapedHTMLString(mail.getUserFirstName(member)), host, prid);
222228
mail.sendMessage(member.email, properties["mail.password-reset-subject"], message);

api/utils/common.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,14 @@ function getJSON(val) {
181181
}
182182
return ret;
183183
}
184+
184185
/**
185-
* Logger object for creating module specific logging
186-
* @type {module:api/utils/log~Logger}
187-
* @example
188-
* var log = common.log('myplugin:api');
189-
* log.i('myPlugin got a request: %j', params.qstring);
190-
*/
186+
* Logger object for creating module-specific logging
187+
* @type {function(string): Logger}
188+
* @example
189+
* const log = common.log('myplugin:api');
190+
* log.i('myPlugin got a request: %j', params.qstring);
191+
*/
191192
common.log = logger;
192193

193194
/**

0 commit comments

Comments
 (0)