Skip to content

Commit e994b4b

Browse files
Merge branch 'next' into SER-1556
2 parents 8d1bf55 + 6f4f35b commit e994b4b

File tree

48 files changed

+2072
-610
lines changed

Some content is hidden

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

48 files changed

+2072
-610
lines changed

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
"node": true
213213
},
214214
"parserOptions": {
215-
"ecmaVersion": 2020
215+
"ecmaVersion": 2023
216216
},
217217
"rules": {
218218
"no-console": "off",

.github/workflows/main.yml

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ on:
1010

1111
# Allows you to run this workflow manually from the Actions tab
1212
workflow_dispatch:
13+
inputs:
14+
custom_tag:
15+
description: 'Custom Docker tag (optional)'
16+
required: false
17+
default: ''
1318

1419
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
1520
jobs:
@@ -64,7 +69,7 @@ jobs:
6469

6570
services:
6671
mongodb:
67-
image: mongo:7.0
72+
image: mongo:8.0
6873
options: >-
6974
--health-cmd mongosh
7075
--health-interval 10s
@@ -74,7 +79,7 @@ jobs:
7479
- 27017:27017
7580

7681
container:
77-
image: countly/countly-core:pipelines-${{ github.base_ref || github.ref_name }}
82+
image: countly/countly-core:pipelines-${{ inputs.custom_tag || github.base_ref || github.ref_name }}
7883
env:
7984
COUNTLY_CONFIG__MONGODB_HOST: mongodb
8085
COUNTLY_CONFIG_API_PREVENT_JOBS: true
@@ -121,7 +126,7 @@ jobs:
121126

122127
services:
123128
mongodb:
124-
image: mongo:7.0
129+
image: mongo:8.0
125130
options: >-
126131
--health-cmd mongosh
127132
--health-interval 10s
@@ -131,7 +136,7 @@ jobs:
131136
- 27017:27017
132137

133138
container:
134-
image: countly/countly-core:pipelines-${{ github.base_ref || github.ref_name }}
139+
image: countly/countly-core:pipelines-${{ inputs.custom_tag || github.base_ref || github.ref_name }}
135140
env:
136141
COUNTLY_CONFIG__MONGODB_HOST: mongodb
137142
COUNTLY_CONFIG_API_PREVENT_JOBS: true
@@ -173,7 +178,7 @@ jobs:
173178

174179
services:
175180
mongodb:
176-
image: mongo:7.0
181+
image: mongo:8.0
177182
options: >-
178183
--health-cmd mongosh
179184
--health-interval 10s
@@ -183,7 +188,7 @@ jobs:
183188
- 27017:27017
184189

185190
container:
186-
image: countly/countly-core:pipelines-${{ github.base_ref || github.ref_name }}
191+
image: countly/countly-core:pipelines-${{ inputs.custom_tag || github.base_ref || github.ref_name }}
187192
env:
188193
COUNTLY_CONFIG__MONGODB_HOST: mongodb
189194
COUNTLY_CONFIG_API_PREVENT_JOBS: true
@@ -231,7 +236,7 @@ jobs:
231236

232237
services:
233238
mongodb:
234-
image: mongo:7.0
239+
image: mongo:8.0
235240
options: >-
236241
--health-cmd mongosh
237242
--health-interval 10s
@@ -241,7 +246,7 @@ jobs:
241246
- 27017:27017
242247

243248
container:
244-
image: countly/countly-core:pipelines-${{ github.base_ref || github.ref_name }}
249+
image: countly/countly-core:pipelines-${{ inputs.custom_tag || github.base_ref || github.ref_name }}
245250
env:
246251
COUNTLY_CONFIG__MONGODB_HOST: mongodb
247252
COUNTLY_CONFIG_API_PREVENT_JOBS: true
@@ -296,7 +301,8 @@ jobs:
296301
/sbin/my_init &
297302
cd ui-tests
298303
npm install
299-
npm run cy:run:dashboard
304+
xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" \
305+
npm run cy:run:dashboard --headless --no-sandbox --disable-gpu --disable-dev-shm-usage
300306
301307
- name: Upload UI tests artifacts
302308
if: ${{ failure() }}
@@ -313,7 +319,7 @@ jobs:
313319

314320
services:
315321
mongodb:
316-
image: mongo:6.0
322+
image: mongo:8.0
317323
options: >-
318324
--health-cmd mongosh
319325
--health-interval 10s
@@ -323,7 +329,7 @@ jobs:
323329
- 27017:27017
324330

325331
container:
326-
image: countly/countly-core:pipelines-${{ github.base_ref || github.ref_name }}
332+
image: countly/countly-core:pipelines-${{ inputs.custom_tag || github.base_ref || github.ref_name }}
327333
env:
328334
COUNTLY_CONFIG__MONGODB_HOST: mongodb
329335
COUNTLY_CONFIG_API_PREVENT_JOBS: true
@@ -374,7 +380,8 @@ jobs:
374380
/sbin/my_init &
375381
cd ui-tests
376382
npm install
377-
npm run cy:run:onboarding
383+
xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" \
384+
npm run cy:run:onboarding --headless --no-sandbox --disable-gpu --disable-dev-shm-usage
378385
379386
- name: Upload UI tests artifacts
380387
if: ${{ failure() }}

Gruntfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ module.exports = function(grunt) {
144144
'frontend/express/public/javascripts/countly/vue/components/date.js',
145145
'frontend/express/public/javascripts/countly/vue/components/dropdown.js',
146146
'frontend/express/public/javascripts/countly/vue/components/input.js',
147+
'frontend/express/public/javascripts/countly/vue/components/content.js',
147148
'frontend/express/public/javascripts/countly/vue/datatable-legacy.js',
148149
'frontend/express/public/javascripts/countly/vue/components/datatable.js',
149150
'frontend/express/public/javascripts/countly/vue/components/dialog.js',

api/parts/mgmt/app_users.js

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ usersApi.merge = function(app_id, newAppUser, new_id, old_id, new_device_id, old
764764
var deleteMyExport = function(exportID) { //tries to delete packed file, exported folder and saved export in gridfs
765765
//normally there should be only export in gridfs. Cleaning all to be sure.
766766
//rejects only if there stays any saved data for export
767+
log.d("deleteMyExport:" + exportID);
767768
return new Promise(function(resolve, reject) {
768769
//remove archive
769770
var errors = [];
@@ -775,7 +776,6 @@ var deleteMyExport = function(exportID) { //tries to delete packed file, exporte
775776
errors.push(err);
776777
}
777778
}
778-
779779
countlyFs.gridfs.deleteFile("appUsers", path.resolve(__dirname, './../../../export/AppUser/' + exportID + '.tar.gz'), {id: exportID + '.tar.gz'}, function(error) {
780780
if (error && error.message && error.message.substring(0, 12) !== "FileNotFound" && error.message.substring(0, 14) !== 'File not found') {
781781
log.e(error.message.substring(0, 14));
@@ -806,6 +806,18 @@ var deleteMyExport = function(exportID) { //tries to delete packed file, exporte
806806
}
807807
});
808808

809+
810+
}).then(function() {
811+
return new Promise(function(resolve, reject) {
812+
common.db.collection("exports").remove({"_eid": exportID}, function(err0) {
813+
if (err0) {
814+
reject(err0);
815+
}
816+
else {
817+
resolve();
818+
}
819+
});
820+
});
809821
});
810822
};
811823

@@ -822,46 +834,42 @@ usersApi.deleteExport = function(filename, params, callback) {
822834
//remove archive
823835
deleteMyExport(base_name[0]).then(
824836
function() {
825-
common.db.collection("exports").remove({"_eid": base_name[0]}, function(err0) {
826-
if (err0) {
827-
log.e(err0);
828-
}
829-
if (name_parts.length === 3 && name_parts[2] !== 'HASH') {
830-
//update user info
831-
common.db.collection('app_users' + name_parts[1]).update({"uid": name_parts[2]}, {$unset: {"appUserExport": ""}}, {upsert: false, multi: true}, function(err) {
832-
if (err) {
833-
callback(err, "");
834-
}
835-
else {
836-
plugins.dispatch("/systemlogs", {
837-
params: params,
838-
action: "export_app_user_deleted",
839-
data: {
840-
result: "ok",
841-
uids: name_parts[2],
842-
id: base_name[0],
843-
app_id: name_parts[1],
844-
info: "Exported data deleted"
845-
}
846-
});
847-
callback(null, "Export deleted");
848-
}
849-
});
850-
}
851-
else {
852-
plugins.dispatch("/systemlogs", {
853-
params: params,
854-
action: "export_app_user_deleted",
855-
data: {
856-
result: "ok",
857-
id: base_name[0],
858-
app_id: name_parts[1],
859-
info: "Exported data deleted"
860-
}
861-
});
862-
callback(null, "Export deleted");
863-
}
864-
});
837+
if (name_parts.length === 3 && name_parts[2] !== 'HASH') {
838+
//update user info
839+
common.db.collection('app_users' + name_parts[1]).update({"uid": name_parts[2]}, {$unset: {"appUserExport": ""}}, {upsert: false, multi: true}, function(err) {
840+
if (err) {
841+
callback(err, "");
842+
}
843+
else {
844+
plugins.dispatch("/systemlogs", {
845+
params: params,
846+
action: "export_app_user_deleted",
847+
data: {
848+
result: "ok",
849+
uids: name_parts[2],
850+
id: base_name[0],
851+
app_id: name_parts[1],
852+
info: "Exported data deleted"
853+
}
854+
});
855+
callback(null, "Export deleted");
856+
}
857+
});
858+
}
859+
else {
860+
plugins.dispatch("/systemlogs", {
861+
params: params,
862+
action: "export_app_user_deleted",
863+
data: {
864+
result: "ok",
865+
id: base_name[0],
866+
app_id: name_parts[1],
867+
info: "Exported data deleted"
868+
}
869+
});
870+
callback(null, "Export deleted");
871+
}
872+
865873
},
866874
function(err) {
867875
console.log(err);
@@ -1073,12 +1081,20 @@ usersApi.export = function(app_id, query, params, callback) {
10731081
// else {
10741082
// resolve();
10751083
// }
1076-
new Promise(function(resolve) {
1077-
log.d("collection marked");
1078-
//export data from metric_changes
10791084

1080-
export_safely({projection: {"appUserExport": 0}, export_id: export_id, app_id: app_id, args: [...dbargs, "--collection", "metric_changes" + app_id, "-q", '{"uid":{"$in": ["' + res[0].uid.join('","') + '"]}}', "--out", export_folder + "/metric_changes" + app_id + ".json"]}).finally(function() {
1081-
resolve();
1085+
//try deleting old export
1086+
deleteMyExport(export_id).then(function(err) {
1087+
if (err) {
1088+
log.e(err);
1089+
}
1090+
log.d("old export deleted");
1091+
return new Promise(function(resolve) {
1092+
log.d("collection marked");
1093+
//export data from metric_changes
1094+
1095+
export_safely({projection: {"appUserExport": 0}, export_id: export_id, app_id: app_id, args: [...dbargs, "--collection", "metric_changes" + app_id, "-q", '{"uid":{"$in": ["' + res[0].uid.join('","') + '"]}}', "--out", export_folder + "/metric_changes" + app_id + ".json"]}).finally(function() {
1096+
resolve();
1097+
});
10821098
});
10831099
}).then(function() {
10841100
log.d("metric_changes exported");

api/utils/countlyFs.js

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,60 @@ countlyFs.gridfs = {};
316316
}
317317
};
318318

319+
/**
320+
* Update file fields by ID
321+
* @param {string} category - collection where the file is stored
322+
* @param {string} id - file id
323+
* @param {object} updateFields - fields to update
324+
* @param {function} callback - function called when updating was completed or errored, providing error object as first param
325+
* @example
326+
* countlyFs.gridfs.updateFileById("test", "66d6c2d770434130c03b7dae", { filename: "newname.png", "metadata.tags": "newtag" }, function(err){
327+
* console.log("Update finished", err);
328+
* });
329+
*/
330+
ob.updateFileById = function(category, id, updateFields, callback) {
331+
if (!db) {
332+
if (callback) {
333+
callback(new Error("Database connection not available"));
334+
}
335+
return;
336+
}
337+
338+
const collection = db.collection(category + ".files");
339+
const setOps = {};
340+
341+
for (const [key, value] of Object.entries(updateFields)) {
342+
setOps[key] = value;
343+
}
344+
345+
collection.findOneAndUpdate(
346+
{ _id: new db.ObjectID(id) },
347+
{ $set: setOps },
348+
{ returnOriginal: true },
349+
function(err, result) {
350+
if (err) {
351+
log.e("Error updating file:", err);
352+
if (callback) {
353+
callback(err);
354+
}
355+
return;
356+
}
357+
358+
if (!result.value) {
359+
if (callback) {
360+
callback(new Error("File not found"));
361+
}
362+
return;
363+
}
364+
365+
log.d("File updated successfully");
366+
if (callback) {
367+
callback(null, result.value);
368+
}
369+
}
370+
);
371+
};
372+
319373
/**
320374
* Delete file from shared system
321375
* @param {string} category - collection where to store data
@@ -601,13 +655,19 @@ countlyFs.gridfs = {};
601655
* console.log("Finished", err);
602656
* });
603657
*/
604-
ob.deleteFileById = function(category, id, callback) {
658+
ob.deleteFileById = async function(category, id, callback) {
605659
var bucket = new GridFSBucket(db, { bucketName: category });
606-
bucket.delete(id, function(error) {
660+
try {
661+
await bucket.delete(id);
607662
if (callback) {
608-
callback(error);
663+
callback(null);
609664
}
610-
});
665+
}
666+
catch (ee) {
667+
if (callback) {
668+
callback(ee);
669+
}
670+
}
611671
};
612672

613673
/**
@@ -641,10 +701,12 @@ countlyFs.gridfs = {};
641701
bucket.find().toArray()
642702
.then((records) => callback(
643703
null,
644-
records.map(({ filename, uploadDate, length }) => ({
704+
records.map(({ _id, filename, uploadDate, length, metadata }) => ({
705+
_id,
645706
filename,
646707
createdOn: uploadDate,
647-
size: length
708+
size: length,
709+
metadata
648710
}))
649711
))
650712
.catch((error) => callback(error, null));

0 commit comments

Comments
 (0)