Skip to content
Open
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
bcba2a3
[dashboards] Do not show error if request is cancelled.
Nov 19, 2025
2920a8a
Merge branch 'master' into anna/master
Cookiezaurs Nov 19, 2025
c2a363d
Merge pull request #6984 from Countly/anna/master
Cookiezaurs Nov 19, 2025
aee8eb3
[core] Do not output password in logs on mongodb connection initialis…
Nov 25, 2025
7e5327e
Merge branch 'master' into anna/master
Cookiezaurs Nov 25, 2025
402b545
Update CHANGELOG for version 25.03.XX fixes
Cookiezaurs Nov 25, 2025
9ece661
Merge pull request #6995 from Countly/anna/master
Cookiezaurs Nov 25, 2025
7fdff1e
Merge branch 'master' into Cookiezaurs-patch-3
Cookiezaurs Nov 25, 2025
b8c8573
[dbviewer]Hide api_key from requests
Nov 25, 2025
127f2a3
[core] Hide error details on render error from response
Nov 25, 2025
1bca9d9
Merge branch 'master' into anna/master
Cookiezaurs Nov 25, 2025
8e2ae4d
Add hosting property
ar2rsawseen Nov 25, 2025
fb7fff6
Merge branch 'master' into ar2rsawseen/master2
ar2rsawseen Nov 26, 2025
e9495d4
[core] Do not throw error on returned group data if there is no segme…
Nov 26, 2025
cf96a76
Merge branch 'anna/master' of https://github.com/Countly/countly-serv…
Nov 26, 2025
38e4c93
Merge pull request #6998 from Countly/anna/master
Cookiezaurs Nov 26, 2025
b20f8d5
Merge branch 'master' into Cookiezaurs-patch-3
Cookiezaurs Nov 26, 2025
5f688b4
Merge pull request #6996 from Countly/Cookiezaurs-patch-3
Cookiezaurs Nov 26, 2025
52b8b16
update changelog
Cookiezaurs Nov 26, 2025
c330838
Merge pull request #7004 from Countly/Cookiezaurs-patch-4
Cookiezaurs Nov 26, 2025
6f31111
Merge branch 'master' into ar2rsawseen/master2
Cookiezaurs Nov 26, 2025
7c01cfe
Updated video video upload folder structure
can-angun Nov 26, 2025
93a32c3
Added a fail step for test
can-angun Nov 26, 2025
afd3ebd
remove videos for passed specs reliably
can-angun Nov 26, 2025
72f3da3
Add existence checks before reading artifact folders
can-angun Nov 26, 2025
9373cd1
Fixed prevent uploading empty artifact folders
can-angun Nov 26, 2025
b998745
Fixed fails of widget cases
can-angun Nov 26, 2025
1cb215f
Fixed pages text problem
can-angun Nov 26, 2025
16cf1a2
Merge branch 'master' into QT-356
can-angun Nov 26, 2025
575b5fa
Fixed downloads can not find fail
can-angun Nov 26, 2025
ffd219d
Merge branch 'QT-356' of github.com:Countly/countly-server into QT-356
can-angun Nov 26, 2025
22a8bb3
Updated text for test
can-angun Nov 26, 2025
8e5dd50
Fixed test fails
can-angun Nov 26, 2025
e531f4b
Merge pull request #7005 from Countly/QT-356
can-angun Nov 26, 2025
f8f91f1
Fixes
ar2rsawseen Nov 26, 2025
d2b2624
Merge branch 'master' into ar2rsawseen/master2
ar2rsawseen Nov 27, 2025
3b355fa
More fixes
ar2rsawseen Nov 27, 2025
a4e90d0
Update CHANGELOG.md
Cookiezaurs Nov 28, 2025
d287168
Merge pull request #7012 from Countly/Cookiezaurs-patch-5
Cookiezaurs Nov 28, 2025
350e28a
Merge branch 'master' into ar2rsawseen/master2
ar2rsawseen Nov 28, 2025
c4d75d0
Delete submodule
ar2rsawseen Nov 28, 2025
adee4bb
Expose cookie configs to ENV
ar2rsawseen Nov 28, 2025
d096adb
Fix dashboard error when dashboard is deleted
ar2rsawseen Nov 28, 2025
b8dc69f
Fix report type check
ar2rsawseen Nov 28, 2025
e0cd863
One more fix
ar2rsawseen Nov 28, 2025
4783d0f
Merge pull request #7000 from Countly/ar2rsawseen/master2
ar2rsawseen Nov 28, 2025
92f6b36
Update CHANGELOG for version 25.03.29
Cookiezaurs Dec 2, 2025
2ac6c72
Merge pull request #7022 from Countly/Cookiezaurs-patch-6
Cookiezaurs Dec 2, 2025
11929bc
Merge branch 'flex' into from-25.03.29
frknbasaran Dec 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ jobs:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
test_type: [dashboard, onboarding]

Expand Down Expand Up @@ -338,6 +339,11 @@ jobs:
working-directory: /opt/countly/ui-tests/cypress
run: |
ARTIFACT_ARCHIVE_NAME="$(date '+%Y%m%d-%H.%M')_${GITHUB_REPOSITORY#*/}_CI#${{ github.run_number }}_${{ matrix.test_type }}.tar.gz"

mkdir -p screenshots videos downloads
tar zcvf "$ARTIFACT_ARCHIVE_NAME" screenshots videos downloads
find screenshots videos downloads -type d -empty -delete

TAR_TARGETS=$(ls -d screenshots videos downloads 2>/dev/null || true)

tar zcvf "$ARTIFACT_ARCHIVE_NAME" $TAR_TARGETS
curl -o /tmp/uploader.log -u "${{ secrets.BOX_UPLOAD_AUTH }}" ${{ secrets.BOX_UPLOAD_PATH }} -T "$ARTIFACT_ARCHIVE_NAME"
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## Version 25.03.29
Fixes:
- [core] Do not output password in logs on mongodb connection initialisation error
- [core] Hide error details on render error from response
- [dashboards] Do not show error if request is cancelled.
- [dbviewer] Hide api_key from requests
- [events] Do not throw error in UI on returned group data if there is no segmentation set

Enterprise Fixes:
- [drill] Fixed timeline recalculation
- [surveys] Do not fetch survey meta data if plugin is disabled

## Version 25.03.28
Fixes:
- [alerts] Add alert interval validation in the frontend
Expand Down
7 changes: 6 additions & 1 deletion api/configextender.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ const OVERRIDES = {
CA: 'ca',
},
},

COOKIE: {
SAMESITE: 'sameSite',
HTTPONLY: 'httpOnly',
MAXAGE: 'maxAge',
MAXAGELOGIN: 'maxAgeLogin',
},
MAIL: {
CONFIG: {
IGNORETLS: "ignoreTLS"
Expand Down
2 changes: 1 addition & 1 deletion api/jobs/ping.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class PingJob extends job.Job {

if (days > 0) {
//calculate seconds timestamp of days before today
var startTs = Math.round((new Date().getTime() - (30 * 24 * 60 * 60 * 1000)) / 1000);
var startTs = Math.round((new Date().getTime() - (days * 24 * 60 * 60 * 1000)) / 1000);

//sync server events - use aggregation pipeline to group by day and action on MongoDB side
var aggregationPipeline = [
Expand Down
7 changes: 7 additions & 0 deletions api/parts/mgmt/tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ tracker.collectServerData = async function() {
edition = "Enterprise";
}
props.edition = edition;
props.hosting = "self-hosted";
if (props.edition === "Flex") {
props.hosting = "flex";
}
else if (props.plugins.includes("tracker")) {
props.hosting = "countly-hosted";
}
if (common.db.build && common.db.build.version) {
props.mongodb = common.db.build.version;
}
Expand Down
3 changes: 3 additions & 0 deletions api/parts/mgmt/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,9 @@ usersApi.checkNoteEditPermission = async function(params) {
if (error) {
return reject(false);
}
if (!note) {
return resolve(false);
}
const globalAdmin = params.member.global_admin;
const isAppAdmin = hasAdminAccess(params.member, params.qstring.app_id);
const noteOwner = (note.owner + '' === params.member._id + '');
Expand Down
4 changes: 2 additions & 2 deletions api/utils/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ common.validateArgs = function(args, argProperties, returnErrors) {
}

if (argProperties[arg]['max-length']) {
if (args[arg].length > argProperties[arg]['max-length']) {
if (args[arg] && args[arg].length > argProperties[arg]['max-length']) {
if (returnErrors) {
returnObj.errors.push("Length of " + arg + " is greater than max length value");
returnObj.result = false;
Expand All @@ -1084,7 +1084,7 @@ common.validateArgs = function(args, argProperties, returnErrors) {
}

if (argProperties[arg]['min-length']) {
if (args[arg].length < argProperties[arg]['min-length']) {
if (args[arg] && args[arg].length < argProperties[arg]['min-length']) {
if (returnErrors) {
returnObj.errors.push("Length of " + arg + " is lower than min length value");
returnObj.result = false;
Expand Down
2 changes: 1 addition & 1 deletion api/utils/requestProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ const processRequest = (params) => {
options.token = token;
render.renderView(options, function(err3) {
if (err3) {
common.returnMessage(params, 400, 'Error creating screenshot: ' + err3);
common.returnMessage(params, 400, 'Error creating screenshot. Please check logs for more information.');
return false;
}
common.returnOutput(params, {path: common.config.path + "/images/screenshots/" + imageName});
Expand Down
1 change: 0 additions & 1 deletion countly-community
Submodule countly-community deleted from f772bc
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@
},
getSegments: function(context, res) {
var segments = [];
if (res.meta && res.meta.segments.length > 0) {
if (res.meta && res.meta.segments && Array.isArray(res.meta.segments) && res.meta.segments.length > 0) {
segments = res.meta.segments.slice();
context.commit('setHasSegments', true);
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/alerts/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ const PERIOD_TO_TEXT_EXPRESSION_MAPPER = {

validateCreate(params, FEATURE_NAME, function() {
let alertConfig = params.qstring.alert_config;
if (!alertConfig) {
common.returnMessage(params, 400, 'Missing alert_config');
return;
}
try {
alertConfig = JSON.parse(alertConfig);
var checkProps = {
Expand Down
6 changes: 3 additions & 3 deletions plugins/compliance-hub/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ const FEATURE_NAME = 'compliance_hub';
case 'current': {
if (!params.qstring.app_id) {
common.returnMessage(params, 400, 'Missing parameter "app_id"');
return false;
return true;
}
validateRead(params, FEATURE_NAME, function() {
var query = params.qstring.query || {};
Expand All @@ -157,7 +157,7 @@ const FEATURE_NAME = 'compliance_hub';
case 'search': {
if (!params.qstring.app_id) {
common.returnMessage(params, 400, 'Missing parameter "app_id"');
return false;
return true;
}
validateRead(params, FEATURE_NAME, function() {
var query = params.qstring.query || {};
Expand Down Expand Up @@ -279,7 +279,7 @@ const FEATURE_NAME = 'compliance_hub';
case 'consents': {
if (!params.qstring.app_id) {
common.returnMessage(params, 400, 'Missing parameter "app_id"');
return false;
return true;
}
validateRead(params, FEATURE_NAME, function() {
appUsers.count(params.qstring.app_id, {}, function(err, total) {
Expand Down
25 changes: 20 additions & 5 deletions plugins/dashboards/frontend/public/javascripts/countly.models.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

(function(countlyDashboards) {

var isRequestCancelled = function(e) {
var isCancelled = false;
if (e && e.statusText === "abort") {
isCancelled = true;
}
return isCancelled;
};
countlyDashboards.factory = {
dashboards: {
getEmpty: function() {
Expand Down Expand Up @@ -66,6 +73,9 @@
}, {disableAutoCatch: true});
},
get: function(dashboardId, isRefresh) {
if (!dashboardId) {
return Promise.resolve(null);
}
return CV.$.ajax({
type: "GET",
url: countlyCommon.API_PARTS.data.r + "/dashboards",
Expand Down Expand Up @@ -643,11 +653,16 @@

return dashbaord;
}).catch(function(e) {
log(e);
CountlyHelpers.notify({
message: "Something went wrong while fetching the dashbaord!",
type: "error"
});
if (!isRequestCancelled(e)) {
log(e);
CountlyHelpers.notify({
message: "Something went wrong while fetching the dashbaord!",
type: "error"
});
}
else {
log("Request cancelled: " + e);
}

return false;
});
Expand Down
8 changes: 5 additions & 3 deletions plugins/dbviewer/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,12 @@ var spawn = require('child_process').spawn,
**/
function getIndexes() {
dbs[dbNameOnParam].collection(params.qstring.collection).indexes(function(err, indexes) {
if (err) {
common.returnOutput(params, 'Somethings went wrong');
if (err || !indexes) {
common.returnOutput(params, 'Failed to retrieve indexes for the collection');
}
else {
common.returnOutput(params, { limit: indexes.length, start: 1, end: indexes.length, total: indexes.length, pages: 1, curPage: 1, collections: indexes });
}
common.returnOutput(params, { limit: indexes.length, start: 1, end: indexes.length, total: indexes.length, pages: 1, curPage: 1, collections: indexes });
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@
sort = JSON.stringify(this.preparedSortObject);
}
var apiQueryData = {
api_key: countlyGlobal.member.api_key,
app_id: countlyCommon.ACTIVE_APP_ID,
//filename: "DBViewer" + moment().format("DD-MMM-YYYY"), - using passed filename from form
projection: JSON.stringify(this.preparedProjectionFields),
Expand Down Expand Up @@ -303,7 +302,7 @@
},
computed: {
dbviewerAPIEndpoint: function() {
var url = '/db?api_key=' + countlyGlobal.member.api_key + '&app_id=' + countlyCommon.ACTIVE_APP_ID + '&dbs=' + this.localDb + '&collection=' + this.localCollection;
var url = '/db?app_id=' + countlyCommon.ACTIVE_APP_ID + '&dbs=' + this.localDb + '&collection=' + this.localCollection;
if (this.queryFilter) {
url += '&filter=' + encodeURIComponent(this.queryFilter);
}
Expand Down
11 changes: 10 additions & 1 deletion plugins/pluginManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -1979,10 +1979,19 @@ var pluginManager = function pluginManager() {
await client.connect();
}
catch (ex) {
var safeDbName = dbName;
var start = dbName.indexOf("://") + 3;
var end = dbName.indexOf("@", start);
if (end > -1 && start > 3) {
var middle = dbName.indexOf(":", start);
if (middle > -1 && middle < end) {
safeDbName = dbName.substring(0, middle) + ":*****" + dbName.substring(end);
}
}
logDbRead.e("Error connecting to database", ex);
logDbRead.e("With params %j", {
db: db_name,
connection: dbName,
connection: safeDbName,
options: dbOptions
});
//exit to retry to reconnect on restart
Expand Down
52 changes: 32 additions & 20 deletions plugins/reports/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ const FEATURE_NAME = 'reports';
}
catch (SyntaxError) {
console.log('Parse ' + paramsInstance.qstring.args + ' JSON failed');
common.returnMessage(paramsInstance, 400, 'Invalid JSON in args');
return true;
}
}

Expand Down Expand Up @@ -218,6 +220,8 @@ const FEATURE_NAME = 'reports';
}
catch (SyntaxError) {
console.log('Parse ' + paramsInstance.qstring.args + ' JSON failed');
common.returnMessage(paramsInstance, 400, 'Invalid JSON in args');
return true;
}
}
const recordUpdateOrDeleteQuery = function(params, recordID) {
Expand Down Expand Up @@ -254,18 +258,22 @@ const FEATURE_NAME = 'reports';

convertToTimezone(props);

// TODO: handle report type check

let userApps = getUserApps(params.member);
let notPermitted = false;
for (var i = 0; i < props.apps.length; i++) {
if (userApps.indexOf(props.apps[i]) === -1) {
notPermitted = true;
if (props.report_type === "core") {
if (!props.apps || !Array.isArray(props.apps) || props.apps.length === 0) {
common.returnMessage(params, 400, 'Invalid or missing apps');
return;
}
}

if (notPermitted && !params.member.global_admin) {
return common.returnMessage(params, 401, 'User does not have right to access this information');
let userApps = getUserApps(params.member);
let notPermitted = false;
for (var i = 0; i < props.apps.length; i++) {
if (userApps.indexOf(props.apps[i]) === -1) {
notPermitted = true;
}
}
if (notPermitted && !params.member.global_admin) {
return common.returnMessage(params, 401, 'User does not have right to access this information');
}
}

common.db.collection('reports').insert(props, function(err0, result) {
Expand Down Expand Up @@ -304,18 +312,22 @@ const FEATURE_NAME = 'reports';

convertToTimezone(props);

// TODO: Handle report type check
const userApps = getUserApps(params.member);
let notPermitted = false;

for (var i = 0; i < props.apps.length; i++) {
if (userApps.indexOf(props.apps[i]) === -1) {
notPermitted = true;
if (props.report_type === "core") {
if (!props.apps || !Array.isArray(props.apps) || props.apps.length === 0) {
common.returnMessage(params, 400, 'Invalid or missing apps');
return;
}
}

if (notPermitted && !params.member.global_admin) {
return common.returnMessage(params, 401, 'User does not have right to access this information');
let userApps = getUserApps(params.member);
let notPermitted = false;
for (var i = 0; i < props.apps.length; i++) {
if (userApps.indexOf(props.apps[i]) === -1) {
notPermitted = true;
}
}
if (notPermitted && !params.member.global_admin) {
return common.returnMessage(params, 401, 'User does not have right to access this information');
}
}
common.db.collection('reports').findOne(recordUpdateOrDeleteQuery(params, id), function(err_update, report) {
if (err_update) {
Expand Down
Loading
Loading