@oneuptime/common 11.5.13 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/EnterpriseLicense.ts +21 -0
- package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +25 -0
- package/Models/DatabaseModels/GlobalConfig.ts +76 -0
- package/Server/API/EnterpriseLicenseAPI.ts +57 -0
- package/Server/API/GlobalConfigAPI.ts +62 -1
- package/Server/EnvironmentConfig.ts +22 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.ts +38 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/AnalyticsDatabaseService.ts +48 -45
- package/Server/Services/DatabaseService.ts +66 -1
- package/Server/Services/WorkflowService.ts +100 -39
- package/Server/Types/Workflow/Components/Schedule.ts +57 -32
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +59 -0
- package/Server/Utils/Express.ts +13 -0
- package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +799 -0
- package/Server/Utils/Telemetry/TelemetryWriterClient.ts +263 -0
- package/Server/Utils/Telemetry/TelemetryWriterServer.ts +240 -0
- package/Server/Utils/Telemetry/TelemetryWriterShedMetrics.ts +93 -0
- package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +232 -0
- package/Tests/Server/Services/UpdateOneByIdKeepsRowId.test.ts +107 -0
- package/Tests/Server/Services/WorkflowService.test.ts +308 -0
- package/Tests/Server/Utils/Attribution.test.ts +203 -0
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +183 -0
- package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +340 -0
- package/Tests/Server/Utils/Monitor/Criteria/ExceptionMonitorCriteria.test.ts +87 -0
- package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +165 -0
- package/Tests/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.test.ts +86 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +1565 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterClient.test.ts +313 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterServer.test.ts +270 -0
- package/Tests/Server/Utils/Telemetry/TelemetryWriterShedMetrics.test.ts +127 -0
- package/Tests/Types/AI/CodeFixTaskType.test.ts +3 -0
- package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +228 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +169 -0
- package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +289 -0
- package/Tests/Types/Monitor/MonitorStepLogMonitor.test.ts +231 -0
- package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +245 -0
- package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +155 -0
- package/Tests/Types/Monitor/MonitorStepTelemetrySerialization.test.ts +141 -0
- package/Tests/Types/Monitor/MonitorStepTraceMonitor.test.ts +137 -0
- package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +311 -0
- package/Tests/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.test.ts +461 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +2852 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +758 -0
- package/Tests/UI/Utils/NotificationMethodUtil.test.ts +564 -0
- package/Tests/Utils/Array.test.ts +156 -0
- package/Tests/Utils/CronTab.test.ts +199 -0
- package/Tests/Utils/ModelImportExport.test.ts +101 -0
- package/Tests/Utils/Number.test.ts +179 -0
- package/Tests/Utils/VersionUtil.test.ts +348 -0
- package/Tests/jest.setup.ts +1 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +6 -0
- package/Types/Monitor/MonitorStep.ts +24 -4
- package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +105 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +445 -12
- package/UI/Components/Workflow/ArgumentsForm.tsx +68 -30
- package/UI/Components/Workflow/CronScheduleField.tsx +411 -0
- package/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.ts +176 -0
- package/UI/Utils/NotificationMethodUtil.ts +310 -0
- package/Utils/CronTab.ts +823 -0
- package/Utils/ModelImportExport.ts +21 -6
- package/Utils/VersionUtil.ts +260 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +22 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +26 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +81 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +47 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +52 -1
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +17 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +44 -16
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +53 -1
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowService.js +80 -30
- package/build/dist/Server/Services/WorkflowService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Schedule.js +44 -19
- package/build/dist/Server/Types/Workflow/Components/Schedule.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js +24 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -0
- package/build/dist/Server/Utils/Express.js +12 -0
- package/build/dist/Server/Utils/Express.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +496 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js +165 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js +136 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js +76 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStep.js +20 -4
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +73 -0
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +261 -13
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +30 -6
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/CronScheduleField.js +209 -0
- package/build/dist/UI/Components/Workflow/CronScheduleField.js.map +1 -0
- package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js +129 -0
- package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js.map +1 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js +189 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -0
- package/build/dist/Utils/CronTab.js +609 -0
- package/build/dist/Utils/CronTab.js.map +1 -0
- package/build/dist/Utils/ModelImportExport.js +20 -6
- package/build/dist/Utils/ModelImportExport.js.map +1 -1
- package/build/dist/Utils/VersionUtil.js +193 -0
- package/build/dist/Utils/VersionUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -102,6 +102,27 @@ export default class EnterpriseLicense extends BaseModel {
|
|
|
102
102
|
})
|
|
103
103
|
public annualContractValue?: number = undefined;
|
|
104
104
|
|
|
105
|
+
@ColumnAccessControl({
|
|
106
|
+
create: [],
|
|
107
|
+
read: [],
|
|
108
|
+
update: [],
|
|
109
|
+
})
|
|
110
|
+
@TableColumn({
|
|
111
|
+
required: true,
|
|
112
|
+
isDefaultValueColumn: true,
|
|
113
|
+
type: TableColumnType.Boolean,
|
|
114
|
+
title: "Evaluation License",
|
|
115
|
+
description:
|
|
116
|
+
"When enabled, this key is for evaluation and testing only — the customer's installation shows an evaluation notice and it is not meant for production use.",
|
|
117
|
+
defaultValue: false,
|
|
118
|
+
})
|
|
119
|
+
@Column({
|
|
120
|
+
nullable: false,
|
|
121
|
+
type: ColumnType.Boolean,
|
|
122
|
+
default: false,
|
|
123
|
+
})
|
|
124
|
+
public isEvaluationLicense?: boolean = undefined;
|
|
125
|
+
|
|
105
126
|
@ColumnAccessControl({
|
|
106
127
|
create: [],
|
|
107
128
|
read: [],
|
|
@@ -188,4 +188,29 @@ export default class EnterpriseLicenseInstance extends BaseModel {
|
|
|
188
188
|
nullable: true,
|
|
189
189
|
})
|
|
190
190
|
public masterAdminEmails?: Array<string> = undefined;
|
|
191
|
+
|
|
192
|
+
/*
|
|
193
|
+
* Named oneuptimeVersion, not version: DatabaseBaseModel already declares a
|
|
194
|
+
* `version` @VersionColumn() (the optimistic-locking row revision) on every
|
|
195
|
+
* model, so a second `version` property would collide in the TypeORM entity
|
|
196
|
+
* metadata.
|
|
197
|
+
*/
|
|
198
|
+
@ColumnAccessControl({
|
|
199
|
+
create: [],
|
|
200
|
+
read: [],
|
|
201
|
+
update: [],
|
|
202
|
+
})
|
|
203
|
+
@TableColumn({
|
|
204
|
+
required: false,
|
|
205
|
+
type: TableColumnType.ShortText,
|
|
206
|
+
title: "OneUptime Version",
|
|
207
|
+
description:
|
|
208
|
+
"OneUptime version this instance last reported, for example 11.5.13. Lets support see which instances are running an outdated build.",
|
|
209
|
+
})
|
|
210
|
+
@Column({
|
|
211
|
+
nullable: true,
|
|
212
|
+
type: ColumnType.ShortText,
|
|
213
|
+
length: ColumnLength.ShortText,
|
|
214
|
+
})
|
|
215
|
+
public oneuptimeVersion?: string = undefined;
|
|
191
216
|
}
|
|
@@ -824,6 +824,25 @@ export default class GlobalConfig extends GlobalConfigModel {
|
|
|
824
824
|
})
|
|
825
825
|
public enterpriseLicenseToken?: string = undefined;
|
|
826
826
|
|
|
827
|
+
@ColumnAccessControl({
|
|
828
|
+
create: [],
|
|
829
|
+
read: [],
|
|
830
|
+
update: [],
|
|
831
|
+
})
|
|
832
|
+
@TableColumn({
|
|
833
|
+
type: TableColumnType.Boolean,
|
|
834
|
+
title: "Enterprise License Is Evaluation",
|
|
835
|
+
description:
|
|
836
|
+
"True when the validated enterprise license is an evaluation/testing license. Drives the evaluation notice shown in the edition modal.",
|
|
837
|
+
defaultValue: false,
|
|
838
|
+
})
|
|
839
|
+
@Column({
|
|
840
|
+
type: ColumnType.Boolean,
|
|
841
|
+
nullable: true,
|
|
842
|
+
default: false,
|
|
843
|
+
})
|
|
844
|
+
public enterpriseLicenseIsEvaluation?: boolean = undefined;
|
|
845
|
+
|
|
827
846
|
@ColumnAccessControl({
|
|
828
847
|
create: [],
|
|
829
848
|
read: [],
|
|
@@ -929,6 +948,63 @@ export default class GlobalConfig extends GlobalConfigModel {
|
|
|
929
948
|
})
|
|
930
949
|
public enterpriseLicenseExpiryReminderDays?: number = undefined;
|
|
931
950
|
|
|
951
|
+
/*
|
|
952
|
+
* The four latestRelease* columns cache the daily GitHub release check
|
|
953
|
+
* (Workers/Jobs/InstanceUpdate/CheckForNewVersion). They are a cache, not
|
|
954
|
+
* configuration: an air-gapped installation simply leaves them null and no
|
|
955
|
+
* update prompt is ever shown.
|
|
956
|
+
*/
|
|
957
|
+
@ColumnAccessControl({
|
|
958
|
+
create: [],
|
|
959
|
+
read: [],
|
|
960
|
+
update: [],
|
|
961
|
+
})
|
|
962
|
+
@TableColumn({
|
|
963
|
+
type: TableColumnType.ShortText,
|
|
964
|
+
title: "Latest Release Version",
|
|
965
|
+
description:
|
|
966
|
+
"Latest OneUptime version published on GitHub, for example 11.6.0, as of the last update check. Null until the first successful check.",
|
|
967
|
+
})
|
|
968
|
+
@Column({
|
|
969
|
+
type: ColumnType.ShortText,
|
|
970
|
+
length: ColumnLength.ShortText,
|
|
971
|
+
nullable: true,
|
|
972
|
+
})
|
|
973
|
+
public latestReleaseVersion?: string = undefined;
|
|
974
|
+
|
|
975
|
+
@ColumnAccessControl({
|
|
976
|
+
create: [],
|
|
977
|
+
read: [],
|
|
978
|
+
update: [],
|
|
979
|
+
})
|
|
980
|
+
@TableColumn({
|
|
981
|
+
type: TableColumnType.Date,
|
|
982
|
+
title: "Latest Release Published At",
|
|
983
|
+
description: "When the latest OneUptime version was published on GitHub.",
|
|
984
|
+
})
|
|
985
|
+
@Column({
|
|
986
|
+
type: ColumnType.Date,
|
|
987
|
+
nullable: true,
|
|
988
|
+
})
|
|
989
|
+
public latestReleasePublishedAt?: Date = undefined;
|
|
990
|
+
|
|
991
|
+
@ColumnAccessControl({
|
|
992
|
+
create: [],
|
|
993
|
+
read: [],
|
|
994
|
+
update: [],
|
|
995
|
+
})
|
|
996
|
+
@TableColumn({
|
|
997
|
+
type: TableColumnType.Date,
|
|
998
|
+
title: "Latest Release Checked At",
|
|
999
|
+
description:
|
|
1000
|
+
"When this installation last successfully checked GitHub for a newer OneUptime release.",
|
|
1001
|
+
})
|
|
1002
|
+
@Column({
|
|
1003
|
+
type: ColumnType.Date,
|
|
1004
|
+
nullable: true,
|
|
1005
|
+
})
|
|
1006
|
+
public latestReleaseCheckedAt?: Date = undefined;
|
|
1007
|
+
|
|
932
1008
|
@ColumnAccessControl({
|
|
933
1009
|
create: [],
|
|
934
1010
|
read: [],
|
|
@@ -5,6 +5,7 @@ import { JSONObject } from "../../Types/JSON";
|
|
|
5
5
|
import PartialEntity from "../../Types/Database/PartialEntity";
|
|
6
6
|
import EnterpriseLicenseInstanceSummary from "../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
|
|
7
7
|
import EnterpriseLicenseUsageUtil from "../../Utils/EnterpriseLicense/EnterpriseLicenseUsage";
|
|
8
|
+
import VersionUtil from "../../Utils/VersionUtil";
|
|
8
9
|
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
9
10
|
import ObjectID from "../../Types/ObjectID";
|
|
10
11
|
import PositiveNumber from "../../Types/PositiveNumber";
|
|
@@ -29,6 +30,8 @@ export interface LicenseInstanceUpsert {
|
|
|
29
30
|
licenseId: ObjectID;
|
|
30
31
|
instanceId: string;
|
|
31
32
|
host: string | undefined;
|
|
33
|
+
// OneUptime version the instance is running. Absent on instances too old to report it.
|
|
34
|
+
oneuptimeVersion?: string | null | undefined;
|
|
32
35
|
// Usage fields are only set on report-user-count, not on validate.
|
|
33
36
|
userCount?: number | undefined;
|
|
34
37
|
userEmailHashes?: Array<string> | undefined;
|
|
@@ -84,6 +87,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
84
87
|
userLimit: true,
|
|
85
88
|
currentUserCount: true,
|
|
86
89
|
userCountUpdatedAt: true,
|
|
90
|
+
isEvaluationLicense: true,
|
|
87
91
|
},
|
|
88
92
|
props: {
|
|
89
93
|
isRoot: true,
|
|
@@ -117,12 +121,16 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
117
121
|
req.body["instanceId"],
|
|
118
122
|
);
|
|
119
123
|
const instanceHost: string = this.parseShortText(req.body["host"]);
|
|
124
|
+
const instanceVersion: string | null | undefined = this.parseVersion(
|
|
125
|
+
req.body["version"],
|
|
126
|
+
);
|
|
120
127
|
|
|
121
128
|
if (instanceId) {
|
|
122
129
|
await this.upsertLicenseInstance({
|
|
123
130
|
licenseId: license.id!,
|
|
124
131
|
instanceId: instanceId,
|
|
125
132
|
host: instanceHost || undefined,
|
|
133
|
+
oneuptimeVersion: instanceVersion,
|
|
126
134
|
});
|
|
127
135
|
}
|
|
128
136
|
|
|
@@ -154,6 +162,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
154
162
|
userCountUpdatedAt: license.userCountUpdatedAt
|
|
155
163
|
? license.userCountUpdatedAt.toISOString()
|
|
156
164
|
: null,
|
|
165
|
+
isEvaluationLicense: Boolean(license.isEvaluationLicense),
|
|
157
166
|
instances: this.getInstanceSummaries(instances),
|
|
158
167
|
token,
|
|
159
168
|
});
|
|
@@ -196,6 +205,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
196
205
|
select: {
|
|
197
206
|
_id: true,
|
|
198
207
|
userLimit: true,
|
|
208
|
+
isEvaluationLicense: true,
|
|
199
209
|
},
|
|
200
210
|
props: {
|
|
201
211
|
isRoot: true,
|
|
@@ -212,6 +222,9 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
212
222
|
req.body["instanceId"],
|
|
213
223
|
);
|
|
214
224
|
const instanceHost: string = this.parseShortText(req.body["host"]);
|
|
225
|
+
const instanceVersion: string | null | undefined = this.parseVersion(
|
|
226
|
+
req.body["version"],
|
|
227
|
+
);
|
|
215
228
|
const userEmailHashes: Array<string> =
|
|
216
229
|
EnterpriseLicenseUsageUtil.sanitizeUserEmailHashes(
|
|
217
230
|
req.body["userEmailHashes"],
|
|
@@ -230,6 +243,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
230
243
|
licenseId: license.id!,
|
|
231
244
|
instanceId: instanceId,
|
|
232
245
|
host: instanceHost || undefined,
|
|
246
|
+
oneuptimeVersion: instanceVersion,
|
|
233
247
|
userCount: userCount,
|
|
234
248
|
userEmailHashes: userEmailHashes,
|
|
235
249
|
masterAdminEmails: masterAdminEmails,
|
|
@@ -273,6 +287,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
273
287
|
userCountUpdatedAt: reportedAt.toISOString(),
|
|
274
288
|
userLimit:
|
|
275
289
|
typeof license.userLimit === "number" ? license.userLimit : null,
|
|
290
|
+
isEvaluationLicense: Boolean(license.isEvaluationLicense),
|
|
276
291
|
instances: this.getInstanceSummaries(instances),
|
|
277
292
|
});
|
|
278
293
|
} catch (err) {
|
|
@@ -290,6 +305,31 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
290
305
|
return value.trim().substring(0, 100);
|
|
291
306
|
}
|
|
292
307
|
|
|
308
|
+
/*
|
|
309
|
+
* report-user-count is unauthenticated, so the reported version is only
|
|
310
|
+
* stored when it is a version we could actually compare against a release —
|
|
311
|
+
* garbage never reaches the admin dashboard or the customer's modal.
|
|
312
|
+
*
|
|
313
|
+
* Three outcomes, and the callers depend on the distinction:
|
|
314
|
+
* undefined — the instance sent no version at all (it predates this
|
|
315
|
+
* field). Leave whatever is stored alone.
|
|
316
|
+
* null — it sent something, but not a version. Clear the stored
|
|
317
|
+
* value, so an instance rolled back to a build with no
|
|
318
|
+
* APP_VERSION stops advertising the version it used to run.
|
|
319
|
+
* string — a valid, canonical version to store.
|
|
320
|
+
*/
|
|
321
|
+
private parseVersion(value: unknown): string | null | undefined {
|
|
322
|
+
if (value === undefined || value === null) {
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/*
|
|
327
|
+
* Canonicalized rather than passed through, so the stored string is never
|
|
328
|
+
* something the UIs would render with a doubled "v".
|
|
329
|
+
*/
|
|
330
|
+
return VersionUtil.canonicalize(value);
|
|
331
|
+
}
|
|
332
|
+
|
|
293
333
|
private async findLicenseInstances(
|
|
294
334
|
licenseId: ObjectID,
|
|
295
335
|
): Promise<Array<EnterpriseLicenseInstance>> {
|
|
@@ -304,6 +344,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
304
344
|
userCount: true,
|
|
305
345
|
userEmailHashes: true,
|
|
306
346
|
lastReportedAt: true,
|
|
347
|
+
oneuptimeVersion: true,
|
|
307
348
|
},
|
|
308
349
|
sort: {
|
|
309
350
|
createdAt: SortOrder.Ascending,
|
|
@@ -331,6 +372,7 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
331
372
|
lastReportedAt: instance.lastReportedAt
|
|
332
373
|
? instance.lastReportedAt.toISOString()
|
|
333
374
|
: null,
|
|
375
|
+
version: instance.oneuptimeVersion || null,
|
|
334
376
|
};
|
|
335
377
|
},
|
|
336
378
|
);
|
|
@@ -370,6 +412,11 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
370
412
|
newInstance.host = data.host;
|
|
371
413
|
}
|
|
372
414
|
|
|
415
|
+
// Null means "reported something that is not a version" — nothing to store.
|
|
416
|
+
if (data.oneuptimeVersion) {
|
|
417
|
+
newInstance.oneuptimeVersion = data.oneuptimeVersion;
|
|
418
|
+
}
|
|
419
|
+
|
|
373
420
|
if (data.userCount !== undefined) {
|
|
374
421
|
newInstance.userCount = data.userCount;
|
|
375
422
|
}
|
|
@@ -434,6 +481,16 @@ export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
|
434
481
|
updateData.host = data.host;
|
|
435
482
|
}
|
|
436
483
|
|
|
484
|
+
/*
|
|
485
|
+
* Null clears the column: an instance rebuilt onto a build with no
|
|
486
|
+
* APP_VERSION must stop advertising the version it used to run, because
|
|
487
|
+
* lastReportedAt is refreshed on the same request and would otherwise
|
|
488
|
+
* read as "confirmed running v11.5.13 as of today".
|
|
489
|
+
*/
|
|
490
|
+
if (data.oneuptimeVersion !== undefined) {
|
|
491
|
+
updateData.oneuptimeVersion = data.oneuptimeVersion;
|
|
492
|
+
}
|
|
493
|
+
|
|
437
494
|
if (data.userCount !== undefined) {
|
|
438
495
|
updateData.userCount = data.userCount;
|
|
439
496
|
}
|
|
@@ -17,8 +17,14 @@ import API from "../../Utils/API";
|
|
|
17
17
|
import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
|
|
18
18
|
import HTTPResponse from "../../Types/API/HTTPResponse";
|
|
19
19
|
import PartialEntity from "../../Types/Database/PartialEntity";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
AppVersion,
|
|
22
|
+
DisableUpdateCheck,
|
|
23
|
+
EnterpriseLicenseValidationUrl,
|
|
24
|
+
Host,
|
|
25
|
+
} from "../EnvironmentConfig";
|
|
21
26
|
import EnterpriseLicenseInstanceSummary from "../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
|
|
27
|
+
import VersionUtil from "../../Utils/VersionUtil";
|
|
22
28
|
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
23
29
|
|
|
24
30
|
export default class GlobalConfigAPI extends BaseAPI<
|
|
@@ -67,11 +73,15 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
67
73
|
enterpriseLicenseExpiresAt: true,
|
|
68
74
|
enterpriseLicenseKey: true,
|
|
69
75
|
enterpriseLicenseToken: true,
|
|
76
|
+
enterpriseLicenseIsEvaluation: true,
|
|
70
77
|
enterpriseLicenseUserLimit: true,
|
|
71
78
|
enterpriseLicenseCurrentUserCount: true,
|
|
72
79
|
enterpriseLicenseUserCountUpdatedAt: true,
|
|
73
80
|
enterpriseLicenseInstances: true,
|
|
74
81
|
instanceId: true,
|
|
82
|
+
latestReleaseVersion: true,
|
|
83
|
+
latestReleasePublishedAt: true,
|
|
84
|
+
latestReleaseCheckedAt: true,
|
|
75
85
|
},
|
|
76
86
|
props: {
|
|
77
87
|
isRoot: true,
|
|
@@ -106,6 +116,12 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
106
116
|
? config?.enterpriseLicenseToken || null
|
|
107
117
|
: null,
|
|
108
118
|
licenseValid: licenseValid,
|
|
119
|
+
/*
|
|
120
|
+
* Whether this is an evaluation/testing license. Benign like the
|
|
121
|
+
* company name and expiry, so it is not gated behind sign-in — the
|
|
122
|
+
* edition modal shows the evaluation notice to anyone who opens it.
|
|
123
|
+
*/
|
|
124
|
+
isEvaluationLicense: Boolean(config?.enterpriseLicenseIsEvaluation),
|
|
109
125
|
userLimit:
|
|
110
126
|
typeof config?.enterpriseLicenseUserLimit === "number"
|
|
111
127
|
? config.enterpriseLicenseUserLimit
|
|
@@ -126,6 +142,38 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
126
142
|
isAuthenticatedUser && config?.instanceId
|
|
127
143
|
? config.instanceId.toString()
|
|
128
144
|
: null,
|
|
145
|
+
/*
|
|
146
|
+
* Which build this installation runs, and whether a newer one has
|
|
147
|
+
* been released, are gated the same way as the instance topology:
|
|
148
|
+
* telling an anonymous visitor on the login page that this server
|
|
149
|
+
* is behind on patches advertises an unpatched target.
|
|
150
|
+
*/
|
|
151
|
+
currentVersion: isAuthenticatedUser ? AppVersion : null,
|
|
152
|
+
latestVersion: isAuthenticatedUser
|
|
153
|
+
? config?.latestReleaseVersion || null
|
|
154
|
+
: null,
|
|
155
|
+
latestVersionPublishedAt:
|
|
156
|
+
isAuthenticatedUser && config?.latestReleasePublishedAt
|
|
157
|
+
? config.latestReleasePublishedAt.toISOString()
|
|
158
|
+
: null,
|
|
159
|
+
latestVersionCheckedAt:
|
|
160
|
+
isAuthenticatedUser && config?.latestReleaseCheckedAt
|
|
161
|
+
? config.latestReleaseCheckedAt.toISOString()
|
|
162
|
+
: null,
|
|
163
|
+
isUpdateAvailable: isAuthenticatedUser
|
|
164
|
+
? VersionUtil.isUpdateAvailable({
|
|
165
|
+
currentVersion: AppVersion,
|
|
166
|
+
latestVersion: config?.latestReleaseVersion,
|
|
167
|
+
})
|
|
168
|
+
: false,
|
|
169
|
+
/*
|
|
170
|
+
* Lets the modal say "update checks are off" instead of "has not
|
|
171
|
+
* checked yet", which would be a promise the installation is never
|
|
172
|
+
* going to keep.
|
|
173
|
+
*/
|
|
174
|
+
isUpdateCheckDisabled: isAuthenticatedUser
|
|
175
|
+
? DisableUpdateCheck
|
|
176
|
+
: false,
|
|
129
177
|
};
|
|
130
178
|
|
|
131
179
|
return Response.sendJsonObjectResponse(req, res, responseBody);
|
|
@@ -179,6 +227,12 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
179
227
|
licenseKey,
|
|
180
228
|
instanceId: instanceId.toString(),
|
|
181
229
|
host: Host,
|
|
230
|
+
/*
|
|
231
|
+
* Sent here as well as from the daily report job so the version
|
|
232
|
+
* lands on the license server the moment the key is validated,
|
|
233
|
+
* rather than up to 24 hours later.
|
|
234
|
+
*/
|
|
235
|
+
version: AppVersion,
|
|
182
236
|
},
|
|
183
237
|
});
|
|
184
238
|
|
|
@@ -239,6 +293,9 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
239
293
|
}
|
|
240
294
|
}
|
|
241
295
|
|
|
296
|
+
const isEvaluationLicense: boolean =
|
|
297
|
+
payload["isEvaluationLicense"] === true;
|
|
298
|
+
|
|
242
299
|
const instances: Array<EnterpriseLicenseInstanceSummary> =
|
|
243
300
|
Array.isArray(payload["instances"])
|
|
244
301
|
? (payload[
|
|
@@ -251,6 +308,7 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
251
308
|
enterpriseLicenseKey: licenseKeyRaw || null,
|
|
252
309
|
enterpriseLicenseExpiresAt: licenseExpiry || null,
|
|
253
310
|
enterpriseLicenseToken: licenseToken || null,
|
|
311
|
+
enterpriseLicenseIsEvaluation: isEvaluationLicense,
|
|
254
312
|
enterpriseLicenseUserLimit: userLimit,
|
|
255
313
|
enterpriseLicenseCurrentUserCount: currentUserCount,
|
|
256
314
|
enterpriseLicenseUserCountUpdatedAt: userCountUpdatedAt,
|
|
@@ -287,6 +345,8 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
287
345
|
newConfig.enterpriseLicenseToken = licenseToken;
|
|
288
346
|
}
|
|
289
347
|
|
|
348
|
+
newConfig.enterpriseLicenseIsEvaluation = isEvaluationLicense;
|
|
349
|
+
|
|
290
350
|
if (licenseExpiry) {
|
|
291
351
|
newConfig.enterpriseLicenseExpiresAt = licenseExpiry;
|
|
292
352
|
}
|
|
@@ -321,6 +381,7 @@ export default class GlobalConfigAPI extends BaseAPI<
|
|
|
321
381
|
expiresAt: licenseExpiry ? licenseExpiry.toISOString() : null,
|
|
322
382
|
licenseKey: licenseKeyRaw || null,
|
|
323
383
|
token: licenseToken || null,
|
|
384
|
+
isEvaluationLicense: isEvaluationLicense,
|
|
324
385
|
userLimit: userLimit,
|
|
325
386
|
currentUserCount: currentUserCount,
|
|
326
387
|
userCountUpdatedAt: userCountUpdatedAt
|
|
@@ -665,6 +665,14 @@ export const IpWhitelist: string = process.env["IP_WHITELIST"] || "";
|
|
|
665
665
|
export const DisableTelemetry: boolean =
|
|
666
666
|
process.env["DISABLE_TELEMETRY"] === "true";
|
|
667
667
|
|
|
668
|
+
/*
|
|
669
|
+
* Opt out of the daily "is a newer OneUptime released?" check against the
|
|
670
|
+
* GitHub API. Deliberately separate from DISABLE_TELEMETRY, which turns off
|
|
671
|
+
* the OpenTelemetry SDK and says nothing about outbound calls.
|
|
672
|
+
*/
|
|
673
|
+
export const DisableUpdateCheck: boolean =
|
|
674
|
+
process.env["DISABLE_UPDATE_CHECK"] === "true";
|
|
675
|
+
|
|
668
676
|
export const EnableProfiling: boolean =
|
|
669
677
|
process.env["ENABLE_PROFILING"] === "true";
|
|
670
678
|
|
|
@@ -782,6 +790,20 @@ export const EnterpriseLicenseUserCountReportUrl: URL = URL.fromString(
|
|
|
782
790
|
"https://oneuptime.com/api/enterprise-license/report-user-count",
|
|
783
791
|
);
|
|
784
792
|
|
|
793
|
+
/*
|
|
794
|
+
* GitHub's "latest release" endpoint. It already excludes drafts and
|
|
795
|
+
* prereleases, so whatever it returns is a version an administrator can
|
|
796
|
+
* safely be told to upgrade to.
|
|
797
|
+
*
|
|
798
|
+
* Overridable so an installation with no route to github.com can point the
|
|
799
|
+
* check at an internal mirror instead of turning it off entirely. The mirror
|
|
800
|
+
* must answer with GitHub's release shape (tag_name, html_url, published_at).
|
|
801
|
+
*/
|
|
802
|
+
export const LatestReleaseCheckUrl: URL = URL.fromString(
|
|
803
|
+
process.env["LATEST_RELEASE_CHECK_URL"] ||
|
|
804
|
+
"https://api.github.com/repos/OneUptime/oneuptime/releases/latest",
|
|
805
|
+
);
|
|
806
|
+
|
|
785
807
|
// Inbound Email Configuration for Incoming Email Monitor
|
|
786
808
|
export enum InboundEmailProviderType {
|
|
787
809
|
SendGrid = "SendGrid",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class AddInstanceVersionAndLatestReleaseColumns1784659816363
|
|
4
|
+
implements MigrationInterface
|
|
5
|
+
{
|
|
6
|
+
public name: string =
|
|
7
|
+
"AddInstanceVersionAndLatestReleaseColumns1784659816363";
|
|
8
|
+
|
|
9
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`ALTER TABLE "EnterpriseLicenseInstance" ADD "oneuptimeVersion" character varying(100)`,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`ALTER TABLE "GlobalConfig" ADD "latestReleaseVersion" character varying(100)`,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "GlobalConfig" ADD "latestReleasePublishedAt" TIMESTAMP WITH TIME ZONE`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "GlobalConfig" ADD "latestReleaseCheckedAt" TIMESTAMP WITH TIME ZONE`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "GlobalConfig" DROP COLUMN "latestReleaseCheckedAt"`,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "GlobalConfig" DROP COLUMN "latestReleasePublishedAt"`,
|
|
30
|
+
);
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`ALTER TABLE "GlobalConfig" DROP COLUMN "latestReleaseVersion"`,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "EnterpriseLicenseInstance" DROP COLUMN "oneuptimeVersion"`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class AddEnterpriseLicenseEvaluationColumns1784705487674
|
|
4
|
+
implements MigrationInterface
|
|
5
|
+
{
|
|
6
|
+
public name: string = "AddEnterpriseLicenseEvaluationColumns1784705487674";
|
|
7
|
+
|
|
8
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
9
|
+
await queryRunner.query(
|
|
10
|
+
`ALTER TABLE "EnterpriseLicense" ADD "isEvaluationLicense" boolean NOT NULL DEFAULT false`,
|
|
11
|
+
);
|
|
12
|
+
await queryRunner.query(
|
|
13
|
+
`ALTER TABLE "GlobalConfig" ADD "enterpriseLicenseIsEvaluation" boolean DEFAULT false`,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
18
|
+
await queryRunner.query(
|
|
19
|
+
`ALTER TABLE "GlobalConfig" DROP COLUMN "enterpriseLicenseIsEvaluation"`,
|
|
20
|
+
);
|
|
21
|
+
await queryRunner.query(
|
|
22
|
+
`ALTER TABLE "EnterpriseLicense" DROP COLUMN "isEvaluationLicense"`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -462,6 +462,8 @@ import { AddEnterpriseLicenseNotificationColumns1784218257664 } from "./17842182
|
|
|
462
462
|
import { AddAttributionColumnsToUserAndProject1784293516000 } from "./1784293516000-AddAttributionColumnsToUserAndProject";
|
|
463
463
|
import { AddMarketingConversionTable1784298000000 } from "./1784298000000-AddMarketingConversionTable";
|
|
464
464
|
import { AddExceptionTriageAndPrivacyColumns1784640000000 } from "./1784640000000-AddExceptionTriageAndPrivacyColumns";
|
|
465
|
+
import { AddInstanceVersionAndLatestReleaseColumns1784659816363 } from "./1784659816363-AddInstanceVersionAndLatestReleaseColumns";
|
|
466
|
+
import { AddEnterpriseLicenseEvaluationColumns1784705487674 } from "./1784705487674-AddEnterpriseLicenseEvaluationColumns";
|
|
465
467
|
|
|
466
468
|
export default [
|
|
467
469
|
InitialMigration,
|
|
@@ -928,4 +930,6 @@ export default [
|
|
|
928
930
|
AddAttributionColumnsToUserAndProject1784293516000,
|
|
929
931
|
AddMarketingConversionTable1784298000000,
|
|
930
932
|
AddExceptionTriageAndPrivacyColumns1784640000000,
|
|
933
|
+
AddInstanceVersionAndLatestReleaseColumns1784659816363,
|
|
934
|
+
AddEnterpriseLicenseEvaluationColumns1784705487674,
|
|
931
935
|
];
|