Skip to content

Commit 6a533fb

Browse files
authored
Merge branch 'next' into validating-sidebar-menu
2 parents 228eb9f + 8d33e51 commit 6a533fb

File tree

32 files changed

+832
-229
lines changed

32 files changed

+832
-229
lines changed

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,48 @@
22
Dependencies:
33
- Remove SQLite
44

5+
## Version 25.03.13
6+
Features:
7+
- [remote-config] Enable comparing newer/older app version in conditions
8+
9+
Fixes:
10+
- [remote-config] Fix condition matching with compound conditions
11+
12+
Enterprise Fixes:
13+
- [flows] Showing correct state for disabled flows
14+
- [surveys] Move "not likely" label next to 0 on mobile screens
15+
16+
## Version 25.03.12
17+
Features:
18+
- [plugins] Add configuration warning tags to settings UI
19+
- [white-labeling] Add sidebar footer label setting to white labeling
20+
21+
Fixes:
22+
- [core] Use correct rights validation for loyality
23+
- [crashes] Fix free session for home widget
24+
- [crashes] Fix trend and change calculation for crash stats
25+
- [crashes] Use na for free session and free user when there's no data
26+
- [push] Show segmentation, geo and cohorts related components in push drawer on editing draft.
27+
28+
Enterprise Fixes:
29+
- [ldap] Error handling in ldap plugin on search error
30+
- [license] Display notification for non global admin user
31+
- [users] Load table data from report if user table calculation goes to report manager
32+
33+
Dependencies:
34+
- Bump mongodb from 6.17.0 to 6.18.0
35+
- Bump puppeteer from 24.14.0 to 24.15.0
36+
- Bump supertest from 7.1.3 to 7.1.4
37+
538
## Version 25.03.11
639
Fixes:
740
- [core] Fix mongo connection url parsing
841
- [core] Fix user analytics widget chart
942
- [crashes] Fix free session and free user calculation
1043
- [dashboards] Delete associated widgets and reports when a dashboard is removed
1144
- [star-rating] Fix widget close post message
45+
- [core] Adjust level and update content of app version log
46+
- [populator] Update getVersion to generate valid semantic version
1247

1348
Enterprise Fixes:
1449
- [crash_symbolication] Remove auto symbolication setting

LICENSE renamed to LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Countly Product Analytics - Countly Lite License
33

44
© Countly, https://count.ly
55

6-
Countly is provided under AGPL v3 with modified Section 7. In accordance
6+
Countly is provided under AGPL-3.0 with modified Section 7. In accordance
77
with Section 7 of the AGPL, the Works included in this package or repository
88
(excluding 3rd party Software), are subject to the following additional terms:
99

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,11 @@ If you like Countly, why not use one of our badges and give a link back to us?
116116
<a href="https://countly.com/?utm_source=badge" rel="nofollow"><img style="width:145px;height:60px" src="https://count.ly/badges/light.svg?v2" alt="Countly - Product Analytics" /></a>
117117

118118
<a href="https://countly.com/?utm_source=badge" rel="nofollow"><img style="width:145px;height:60px" src="https://count.ly/badges/light.svg" alt="Countly - Product Analytics" /></a>
119+
120+
121+
## License
122+
This project is licensed under **AGPL-3.0** with modified Section 7., see the [LICENSE](LICENSE) file for more details.
123+
124+
## 💚 Thanks
125+
126+
This project is tested with BrowserStack.

api/parts/data/usage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,7 @@ plugins.register("/sdk/user_properties", async function(ob) {
11211121
userProps.av_build = versionComponents.build;
11221122
}
11231123
else {
1124-
log.w("Invalid app version format: %s", params.qstring.metrics._app_version);
1124+
log.d("App version %s is not a valid semantic version. It cannot be separated into semantic version parts", params.qstring.metrics._app_version);
11251125
userProps.av_major = null;
11261126
userProps.av_minor = null;
11271127
userProps.av_patch = null;

api/utils/requestProcessor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,7 @@ const processRequest = (params) => {
15671567
common.returnMessage(params, 400, 'Missing parameter "app_id"');
15681568
return false;
15691569
}
1570-
validateUserForMgmtReadAPI(countlyApi.mgmt.appUsers.loyalty, params);
1570+
validateUserForRead(params, countlyApi.mgmt.appUsers.loyalty);
15711571
break;
15721572
}
15731573
/**

bin/config/nginx.server.ssl.conf

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@ server {
1111
# HTTPS configuration
1212

1313
server {
14-
listen 443;
15-
listen [::]:443 ipv6only=on;
14+
listen 443 ssl;
15+
listen [::]:443 ipv6only=on;
1616
server_name localhost;
1717

1818
access_log off;
1919

20-
ssl on;
21-
2220
# support only known-secure cryptographic protocols
2321
# SSLv3 is broken by POODLE as of October 2014
2422
ssl_protocols TLSv1.2 TLSv1.3;

bin/scripts/export-data/setting_limits_and_real_values.js

Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* Path: $(countly dir)/bin/scripts/export-data
55
* Command: node setting_limits_and_real_values.js
66
*/
7-
87
const fs = require('fs');
98
const crypto = require('crypto');
109
const common = require('../../../api/utils/common.js');
@@ -20,10 +19,10 @@ const DEFAULT_LIMITS = {
2019
view_name_limit: 128,
2120
view_segment_limit: 100,
2221
view_segment_value_limit: 10,
23-
custom_prop_limit: 20,
22+
//custom_prop_limit: 20,
23+
custom_property_limit: 20,
2424
custom_prop_value_limit: 50,
2525
};
26-
2726
Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("countly_drill")]).then(async function([countlyDb, drillDb]) {
2827
console.log("Connected to databases...");
2928
common.db = countlyDb;
@@ -36,21 +35,17 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
3635
else {
3736
// WRITE START OF ARRAY
3837
WriteStream.write('[\n', 'utf8');
39-
4038
// GETTING DATA FOR SET LIMITS FOR EVENTS, VIEWS, AND CUSTOM PROPERTIES
4139
var pluginsCollectionPlugins = await countlyDb.collection("plugins").findOne({"_id": 'plugins'});
42-
4340
// LOOP APPS FOR EACH REQUIREMENT
4441
for (let i = 0; i < apps.length; i++) {
4542
var app = apps[i];
4643
console.log(i + 1, ") Processing app:", app.name);
47-
4844
try {
4945
var app_results = { "App Name": app.name },
5046
defaultVal,
5147
realVal,
5248
currentVal;
53-
5449
// SETTING UP CURRENT SET LIMITS PER APP
5550
var appsCollectionPerApp = await countlyDb.collection("apps").findOne({"_id": common.db.ObjectID(app._id)});
5651
var CURRENT_LIMITS = {
@@ -61,10 +56,10 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
6156
view_name_limit: pluginsCollectionPlugins?.views?.view_name_limit || DEFAULT_LIMITS.view_name_limit,
6257
view_segment_limit: pluginsCollectionPlugins?.views?.segment_limit || DEFAULT_LIMITS.view_segment_limit,
6358
view_segment_value_limit: pluginsCollectionPlugins?.views?.segment_value_limit || DEFAULT_LIMITS.view_segment_value_limit,
64-
custom_prop_limit: pluginsCollectionPlugins?.users?.custom_prop_limit || DEFAULT_LIMITS.custom_prop_limit,
59+
//custom_prop_limit: pluginsCollectionPlugins?.users?.custom_prop_limit || DEFAULT_LIMITS.custom_prop_limit,
60+
custom_property_limit: pluginsCollectionPlugins?.drill?.custom_property_limit || DEFAULT_LIMITS.custom_property_limit,
6561
custom_prop_value_limit: pluginsCollectionPlugins?.users?.custom_set_limit || DEFAULT_LIMITS.custom_prop_value_limit,
6662
};
67-
6863
// GETTING REAL DATA PER APP
6964
var eventsCollectionPerApp = await countlyDb.collection("events").findOne({"_id": common.db.ObjectID(app._id)});
7065
var viewsCountsPerApp = await countlyDb.collection("app_viewsmeta" + app._id).countDocuments();
@@ -140,46 +135,34 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
140135
catch (err) {
141136
console.log("Mongodb operation failed for app: ", app.name, err);
142137
}
143-
144138
// EVENT KEYS
145139
defaultVal = DEFAULT_LIMITS.event_limit;
146-
147140
currentVal = CURRENT_LIMITS.event_limit;
148-
149141
let realEvents = eventsCollectionPerApp?.list || [];
150142
realVal = realEvents.length;
151-
152143
app_results['Event Keys'] = {"default": defaultVal, "set": currentVal, "real": realVal};
153-
154144
// SEGMENTS IN ONE EVENT
155145
defaultVal = DEFAULT_LIMITS.event_segment_limit;
156-
157146
currentVal = CURRENT_LIMITS.event_segment_limit;
158-
159147
let eventSegments = eventsCollectionPerApp && eventsCollectionPerApp.segments || {};
160148
realVal = Object.entries(eventSegments)
161149
.sort((a, b) => b[1].length - a[1].length)
162150
.reduce((acc, [key, value]) => {
163151
acc[key] = value.length;
164152
return acc;
165153
}, {});
166-
167154
app_results['Event Segments'] = {"default": defaultVal, "set": currentVal, "real": realVal};
168-
169155
// UNIQUE EVENT SEGMENT VALUES FOR 1 SEGMENT
170156
defaultVal = DEFAULT_LIMITS.event_segment_value_limit;
171-
172157
currentVal = CURRENT_LIMITS.event_segment_value_limit;
173-
174158
realVal = {};
175159
await Promise.all(realEvents.map(async(event) => {
176160
var shortEventName = common.fixEventKey(event);
177-
var eventCollectionName = "events" + crypto.createHash('sha1').update(shortEventName + app._id).digest('hex');
178-
161+
var hash = crypto.createHash('sha1').update(shortEventName + app._id).digest('hex');
162+
var eventCollectionName = "events_data";
179163
try {
180164
var regexes = [
181-
"^no-segment_2023:0.*",
182-
"^no-segment_2024:0.*"
165+
"^" + app._id + "_" + hash + "_no-segment_2025:0.*"
183166
];
184167
var eventsSegmentsValues = await countlyDb.collection(eventCollectionName).aggregate([
185168
{
@@ -218,7 +201,6 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
218201
}
219202
}
220203
]).toArray();
221-
222204
// Use reduce to transform array
223205
eventsSegmentsValues = eventsSegmentsValues.reduce((acc, item) => {
224206
const key = item.meta_v2.k;
@@ -228,7 +210,6 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
228210
acc[key] += item.meta_v2.v;
229211
return acc;
230212
}, {});
231-
232213
if (Object.keys(eventsSegmentsValues).length > 0) {
233214
realVal[event] = eventsSegmentsValues;
234215
}
@@ -238,65 +219,45 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
238219
}
239220
}));
240221
app_results['Unique Event Segment Values'] = {"default": defaultVal, "set": currentVal, "real": realVal};
241-
242222
// UNIQUE VIEV NAMES
243223
defaultVal = DEFAULT_LIMITS.view_limit;
244-
245224
currentVal = CURRENT_LIMITS.view_limit;
246-
247225
realVal = viewsCountsPerApp;
248-
249226
app_results['Unique View Names'] = {"default": defaultVal, "set": currentVal, "real": realVal};
250-
251227
// VIEW NAME LENGTH LIMIT
252228
defaultVal = DEFAULT_LIMITS.view_name_limit;
253-
254229
currentVal = CURRENT_LIMITS.view_name_limit;
255-
256230
realVal = {longestViewName: "", longestViewLength: 0};
257231
realVal.longestViewName = viewsCollectionPerApp && viewsCollectionPerApp[0] && viewsCollectionPerApp[0]?.view;
258232
realVal.longestViewLength = viewsCollectionPerApp && viewsCollectionPerApp[0] && viewsCollectionPerApp[0]?.max_length;
259-
260233
app_results['View Name Length Limit'] = {"default": defaultVal, "set": currentVal, "real": realVal};
261-
262234
// SEGMENTS IN ONE VIEW
263235
defaultVal = DEFAULT_LIMITS.view_segment_limit;
264-
265236
currentVal = CURRENT_LIMITS.view_segment_limit;
266-
267237
realVal = viewsSegmentsPerApp && viewsSegmentsPerApp[0]?.numberOfSegments || 0;
268-
269238
app_results['View Segments'] = {"default": defaultVal, "set": currentVal, "real": realVal};
270-
271239
// VIEW SEGMENT'S UNIQUE VALUES
272240
defaultVal = DEFAULT_LIMITS.view_segment_value_limit;
273-
274241
currentVal = CURRENT_LIMITS.view_segment_value_limit;
275-
276242
realVal = viewsSegmentsPerApp && viewsSegmentsPerApp[0]?.segments || 0;
277243
Object.keys(realVal).forEach(key => {
278244
if (realVal[key] === 0) {
279245
delete realVal[key];
280246
}
281247
});
282248
app_results['View Segments Unique Values'] = {"default": defaultVal, "set": currentVal, "real": realVal};
283-
284249
// USER PROPERTIES
285-
defaultVal = DEFAULT_LIMITS.custom_prop_limit;
286-
287-
currentVal = CURRENT_LIMITS.custom_prop_limit;
288-
250+
//defaultVal = DEFAULT_LIMITS.custom_prop_limit;
251+
//currentVal = CURRENT_LIMITS.custom_prop_limit;
252+
defaultVal = DEFAULT_LIMITS.custom_property_limit;
253+
currentVal = CURRENT_LIMITS.custom_property_limit;
289254
realVal = customPropsPerApp && customPropsPerApp[0]?.customPropertiesCount || 0;
290-
app_results['Custom User Properties'] = {"default": defaultVal, "set": currentVal, "real": realVal};
291-
255+
app_results['Max user custom properties'] = {"default": defaultVal, "set": currentVal, "real": realVal};
292256
// VALUES IN AN ARRAY FOR ONE USER PROPERTY
293257
defaultVal = DEFAULT_LIMITS.custom_prop_value_limit;
294-
295258
currentVal = CURRENT_LIMITS.custom_prop_value_limit;
296-
297259
realVal = valueFieldCounts || undefined;
298260
app_results['Values In Array For One User Property'] = {"default": defaultVal, "set": currentVal, "real": realVal};
299-
300261
// WRITE RESULTS PER APP TO FILE
301262
WriteStream.write(JSON.stringify(app_results, null, 2), 'utf8');
302263
if (i + 1 < apps.length) {
@@ -315,7 +276,6 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
315276
finally {
316277
close();
317278
}
318-
319279
async function getAppList(options) {
320280
var query = {};
321281
if (app_list && app_list.length > 0) {
@@ -325,7 +285,6 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
325285
}
326286
query = {_id: {$in: listed}};
327287
}
328-
329288
try {
330289
let apps = await options.db.collection("apps").find(query).toArray();
331290
return apps;
@@ -334,9 +293,7 @@ Promise.all([pluginManager.dbConnection("countly"), pluginManager.dbConnection("
334293
console.log("Error getting apps: ", err);
335294
return [];
336295
}
337-
338296
}
339-
340297
function close(err) {
341298
if (err) {
342299
console.log("Error: ", err);

frontend/express/app.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,14 @@ Promise.all([plugins.dbConnection(countlyConfig), plugins.dbConnection("countly_
422422
app.loadThemeFiles(curTheme);
423423
app.dashboard_headers = plugins.getConfig("security").dashboard_additional_headers;
424424

425+
var overriddenCountlyNamedType = COUNTLY_NAMED_TYPE;
426+
var whiteLabelingConfig = plugins.getConfig("white-labeling");
427+
if (whiteLabelingConfig && whiteLabelingConfig.footerLabel && whiteLabelingConfig.footerLabel.length) {
428+
overriddenCountlyNamedType = whiteLabelingConfig.footerLabel;
429+
}
430+
431+
COUNTLY_NAMED_TYPE = overriddenCountlyNamedType;
432+
425433
if (typeof plugins.getConfig('frontend').countly_tracking !== 'boolean' && plugins.isPluginEnabled('tracker')) {
426434
plugins.updateConfigs(countlyDb, 'frontend', { countly_tracking: true });
427435
}
@@ -929,6 +937,12 @@ Promise.all([plugins.dbConnection(countlyConfig), plugins.dbConnection("countly_
929937
licenseNotification, licenseError;
930938
var isLocked = false;
931939
configs.export_limit = plugins.getConfig("api").export_limit;
940+
941+
var currentWhiteLabelingConfig = plugins.getConfig("white-labeling");
942+
var overriddenCountlyNamedType = COUNTLY_NAMED_TYPE;
943+
if (currentWhiteLabelingConfig && currentWhiteLabelingConfig.footerLabel && currentWhiteLabelingConfig.footerLabel.length) {
944+
overriddenCountlyNamedType = currentWhiteLabelingConfig.footerLabel;
945+
}
932946
app.loadThemeFiles(configs.theme, async function(theme) {
933947
if (configs._user.theme) {
934948
res.cookie("theme", configs.theme);
@@ -1004,7 +1018,7 @@ Promise.all([plugins.dbConnection(countlyConfig), plugins.dbConnection("countly_
10041018
licenseError,
10051019
ssr: serverSideRendering,
10061020
timezones: timezones,
1007-
countlyTypeName: COUNTLY_NAMED_TYPE,
1021+
countlyTypeName: overriddenCountlyNamedType,
10081022
countlyTypeTrack: COUNTLY_TRACK_TYPE,
10091023
countlyTypeCE: COUNTLY_TYPE_CE,
10101024
countly_tracking,
@@ -1037,7 +1051,7 @@ Promise.all([plugins.dbConnection(countlyConfig), plugins.dbConnection("countly_
10371051
countlyVersion: req.countly.version,
10381052
countlyType: COUNTLY_TYPE_CE,
10391053
countlyTrial: COUNTLY_TRIAL,
1040-
countlyTypeName: COUNTLY_NAMED_TYPE,
1054+
countlyTypeName: overriddenCountlyNamedType,
10411055
feedbackLink: COUNTLY_FEEDBACK_LINK,
10421056
documentationLink: COUNTLY_DOCUMENTATION_LINK,
10431057
helpCenterLink: COUNTLY_HELPCENTER_LINK,

0 commit comments

Comments
 (0)