@oneuptime/common 9.5.12 → 10.0.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.
Files changed (76) hide show
  1. package/Models/DatabaseModels/GlobalConfig.ts +19 -0
  2. package/Server/API/UserCallAPI.ts +19 -0
  3. package/Server/API/UserEmailAPI.ts +19 -0
  4. package/Server/API/UserPushAPI.ts +66 -22
  5. package/Server/API/UserSmsAPI.ts +19 -0
  6. package/Server/API/UserWhatsAppAPI.ts +19 -0
  7. package/Server/DatabaseConfig.ts +7 -0
  8. package/Server/EnvironmentConfig.ts +15 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1770834237091-MigrationName.ts +23 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  11. package/Server/Services/ProjectService.ts +14 -0
  12. package/Server/Services/PushNotificationService.ts +136 -12
  13. package/Server/Services/UserNotificationRuleService.ts +153 -111
  14. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +142 -0
  15. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +13 -0
  16. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +21 -0
  17. package/Server/Utils/VM/VMRunner.ts +214 -37
  18. package/Types/Monitor/CriteriaFilter.ts +9 -1
  19. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +15 -0
  20. package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
  21. package/Types/Monitor/MonitorStep.ts +32 -0
  22. package/Types/Monitor/MonitorStepDomainMonitor.ts +33 -0
  23. package/Types/Monitor/MonitorType.ts +66 -2
  24. package/Types/Probe/ProbeMonitorResponse.ts +2 -0
  25. package/UI/Components/CardSelect/CardSelect.tsx +133 -67
  26. package/UI/Components/Forms/Types/Field.ts +7 -2
  27. package/build/dist/Models/DatabaseModels/GlobalConfig.js +21 -0
  28. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  29. package/build/dist/Server/API/UserCallAPI.js +17 -0
  30. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  31. package/build/dist/Server/API/UserEmailAPI.js +17 -0
  32. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  33. package/build/dist/Server/API/UserPushAPI.js +50 -12
  34. package/build/dist/Server/API/UserPushAPI.js.map +1 -1
  35. package/build/dist/Server/API/UserSmsAPI.js +17 -0
  36. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  37. package/build/dist/Server/API/UserWhatsAppAPI.js +17 -0
  38. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  39. package/build/dist/Server/DatabaseConfig.js +9 -0
  40. package/build/dist/Server/DatabaseConfig.js.map +1 -1
  41. package/build/dist/Server/EnvironmentConfig.js +5 -0
  42. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  43. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770834237091-MigrationName.js +14 -0
  44. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770834237091-MigrationName.js.map +1 -0
  45. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  46. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  47. package/build/dist/Server/Services/ProjectService.js +12 -2
  48. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  49. package/build/dist/Server/Services/PushNotificationService.js +74 -12
  50. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  51. package/build/dist/Server/Services/UserNotificationRuleService.js +96 -109
  52. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  53. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +113 -0
  54. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -0
  55. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +10 -0
  56. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  57. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +16 -0
  58. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  59. package/build/dist/Server/Utils/VM/VMRunner.js +182 -20
  60. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  61. package/build/dist/Types/Monitor/CriteriaFilter.js +8 -1
  62. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  63. package/build/dist/Types/Monitor/DomainMonitor/DomainMonitorResponse.js +2 -0
  64. package/build/dist/Types/Monitor/DomainMonitor/DomainMonitorResponse.js.map +1 -0
  65. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
  66. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  67. package/build/dist/Types/Monitor/MonitorStep.js +22 -0
  68. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  69. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +24 -0
  70. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -0
  71. package/build/dist/Types/Monitor/MonitorType.js +58 -2
  72. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  73. package/build/dist/UI/Components/CardSelect/CardSelect.js +55 -20
  74. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  75. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  76. package/package.json +2 -1
@@ -58,6 +58,25 @@ export default class GlobalConfig extends GlobalConfigModel {
58
58
  })
59
59
  public disableSignup?: boolean = undefined;
60
60
 
61
+ @ColumnAccessControl({
62
+ create: [],
63
+ read: [],
64
+ update: [],
65
+ })
66
+ @TableColumn({
67
+ type: TableColumnType.Boolean,
68
+ title: "Disable User Project Creation",
69
+ description: "Only master admins can create projects when enabled.",
70
+ defaultValue: false,
71
+ })
72
+ @Column({
73
+ type: ColumnType.Boolean,
74
+ nullable: true,
75
+ default: false,
76
+ unique: true,
77
+ })
78
+ public disableUserProjectCreation?: boolean = undefined;
79
+
61
80
  // SMTP Settings.
62
81
 
63
82
  @ColumnAccessControl({
@@ -2,6 +2,7 @@ import UserMiddleware from "../Middleware/UserAuthorization";
2
2
  import UserCallService, {
3
3
  Service as UserCallServiceType,
4
4
  } from "../Services/UserCallService";
5
+ import UserNotificationRuleService from "../Services/UserNotificationRuleService";
5
6
  import {
6
7
  ExpressRequest,
7
8
  ExpressResponse,
@@ -9,8 +10,10 @@ import {
9
10
  OneUptimeRequest,
10
11
  } from "../Utils/Express";
11
12
  import Response from "../Utils/Response";
13
+ import logger from "../Utils/Logger";
12
14
  import BaseAPI from "./BaseAPI";
13
15
  import BadDataException from "../../Types/Exception/BadDataException";
16
+ import ObjectID from "../../Types/ObjectID";
14
17
  import UserCall from "../../Models/DatabaseModels/UserCall";
15
18
  import UserSMS from "../../Models/DatabaseModels/UserSMS";
16
19
 
@@ -52,6 +55,7 @@ export default class UserCallAPI extends BaseAPI<
52
55
  },
53
56
  select: {
54
57
  userId: true,
58
+ projectId: true,
55
59
  verificationCode: true,
56
60
  },
57
61
  });
@@ -95,6 +99,21 @@ export default class UserCallAPI extends BaseAPI<
95
99
  },
96
100
  });
97
101
 
102
+ // Create default notification rules for this verified call number
103
+ try {
104
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
105
+ {
106
+ projectId: new ObjectID(item.projectId!.toString()),
107
+ userId: new ObjectID(item.userId!.toString()),
108
+ notificationMethod: {
109
+ userCallId: item.id!,
110
+ },
111
+ },
112
+ );
113
+ } catch (e) {
114
+ logger.error(e);
115
+ }
116
+
98
117
  return Response.sendEmptySuccessResponse(req, res);
99
118
  } catch (err) {
100
119
  return next(err);
@@ -2,6 +2,7 @@ import UserMiddleware from "../Middleware/UserAuthorization";
2
2
  import UserEmailService, {
3
3
  Service as UserEmailServiceType,
4
4
  } from "../Services/UserEmailService";
5
+ import UserNotificationRuleService from "../Services/UserNotificationRuleService";
5
6
  import {
6
7
  ExpressRequest,
7
8
  ExpressResponse,
@@ -9,8 +10,10 @@ import {
9
10
  OneUptimeRequest,
10
11
  } from "../Utils/Express";
11
12
  import Response from "../Utils/Response";
13
+ import logger from "../Utils/Logger";
12
14
  import BaseAPI from "./BaseAPI";
13
15
  import BadDataException from "../../Types/Exception/BadDataException";
16
+ import ObjectID from "../../Types/ObjectID";
14
17
  import UserEmail from "../../Models/DatabaseModels/UserEmail";
15
18
 
16
19
  export default class UserEmailAPI extends BaseAPI<
@@ -51,6 +54,7 @@ export default class UserEmailAPI extends BaseAPI<
51
54
  },
52
55
  select: {
53
56
  userId: true,
57
+ projectId: true,
54
58
  verificationCode: true,
55
59
  },
56
60
  });
@@ -94,6 +98,21 @@ export default class UserEmailAPI extends BaseAPI<
94
98
  },
95
99
  });
96
100
 
101
+ // Create default notification rules for this verified email
102
+ try {
103
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
104
+ {
105
+ projectId: new ObjectID(item.projectId!.toString()),
106
+ userId: new ObjectID(item.userId!.toString()),
107
+ notificationMethod: {
108
+ userEmailId: item.id!,
109
+ },
110
+ },
111
+ );
112
+ } catch (e) {
113
+ logger.error(e);
114
+ }
115
+
97
116
  return Response.sendEmptySuccessResponse(req, res);
98
117
  } catch (err) {
99
118
  return next(err);
@@ -2,8 +2,10 @@ import UserMiddleware from "../Middleware/UserAuthorization";
2
2
  import UserPushService, {
3
3
  Service as UserPushServiceType,
4
4
  } from "../Services/UserPushService";
5
+ import UserNotificationRuleService from "../Services/UserNotificationRuleService";
5
6
  import PushNotificationService from "../Services/PushNotificationService";
6
7
  import PushNotificationUtil from "../Utils/PushNotificationUtil";
8
+ import logger from "../Utils/Logger";
7
9
  import {
8
10
  ExpressRequest,
9
11
  ExpressResponse,
@@ -13,11 +15,23 @@ import {
13
15
  import Response from "../Utils/Response";
14
16
  import BaseAPI from "./BaseAPI";
15
17
  import BadDataException from "../../Types/Exception/BadDataException";
18
+ import NotAuthenticatedException from "../../Types/Exception/NotAuthenticatedException";
16
19
  import ObjectID from "../../Types/ObjectID";
17
20
  import PushDeviceType from "../../Types/PushNotification/PushDeviceType";
18
21
  import UserPush from "../../Models/DatabaseModels/UserPush";
19
22
  import PushNotificationMessage from "../../Types/PushNotification/PushNotificationMessage";
20
23
 
24
+ function getAuthenticatedUserId(req: ExpressRequest): ObjectID {
25
+ const userId: ObjectID | undefined = (req as OneUptimeRequest)
26
+ .userAuthorization?.userId;
27
+ if (!userId) {
28
+ throw new NotAuthenticatedException(
29
+ "You must be logged in to perform this action.",
30
+ );
31
+ }
32
+ return userId;
33
+ }
34
+
21
35
  export default class UserPushAPI extends BaseAPI<
22
36
  UserPush,
23
37
  UserPushServiceType
@@ -32,6 +46,8 @@ export default class UserPushAPI extends BaseAPI<
32
46
  try {
33
47
  req = req as OneUptimeRequest;
34
48
 
49
+ const userId: ObjectID = getAuthenticatedUserId(req);
50
+
35
51
  if (!req.body.deviceToken) {
36
52
  return Response.sendErrorResponse(
37
53
  req,
@@ -65,7 +81,7 @@ export default class UserPushAPI extends BaseAPI<
65
81
  // Check if device is already registered
66
82
  const existingDevice: UserPush | null = await this.service.findOneBy({
67
83
  query: {
68
- userId: (req as OneUptimeRequest).userAuthorization!.userId!,
84
+ userId: userId,
69
85
  projectId: new ObjectID(req.body.projectId),
70
86
  deviceToken: req.body.deviceToken,
71
87
  },
@@ -78,17 +94,18 @@ export default class UserPushAPI extends BaseAPI<
78
94
  });
79
95
 
80
96
  if (existingDevice) {
81
- // Mark as used and return a specific response indicating device was already registered
82
- throw new BadDataException(
83
- "This device is already registered for push notifications",
97
+ return Response.sendErrorResponse(
98
+ req,
99
+ res,
100
+ new BadDataException(
101
+ "This device is already registered for push notifications",
102
+ ),
84
103
  );
85
104
  }
86
105
 
87
106
  // Create new device registration
88
107
  const userPush: UserPush = new UserPush();
89
- userPush.userId = (
90
- req as OneUptimeRequest
91
- ).userAuthorization!.userId!;
108
+ userPush.userId = userId;
92
109
  userPush.projectId = new ObjectID(req.body.projectId);
93
110
  userPush.deviceToken = req.body.deviceToken;
94
111
  userPush.deviceType = req.body.deviceType;
@@ -102,6 +119,21 @@ export default class UserPushAPI extends BaseAPI<
102
119
  },
103
120
  });
104
121
 
122
+ // Create default notification rules for this registered push device
123
+ try {
124
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
125
+ {
126
+ projectId: new ObjectID(req.body.projectId),
127
+ userId,
128
+ notificationMethod: {
129
+ userPushId: savedDevice.id!,
130
+ },
131
+ },
132
+ );
133
+ } catch (e) {
134
+ logger.error(e);
135
+ }
136
+
105
137
  return Response.sendJsonObjectResponse(req, res, {
106
138
  success: true,
107
139
  deviceId: savedDevice._id!.toString(),
@@ -119,6 +151,8 @@ export default class UserPushAPI extends BaseAPI<
119
151
  try {
120
152
  req = req as OneUptimeRequest;
121
153
 
154
+ const userId: ObjectID = getAuthenticatedUserId(req);
155
+
122
156
  if (!req.body.deviceToken) {
123
157
  return Response.sendErrorResponse(
124
158
  req,
@@ -127,9 +161,6 @@ export default class UserPushAPI extends BaseAPI<
127
161
  );
128
162
  }
129
163
 
130
- const userId: ObjectID = (req as OneUptimeRequest).userAuthorization!
131
- .userId!;
132
-
133
164
  await this.service.deleteBy({
134
165
  query: {
135
166
  userId: userId,
@@ -159,6 +190,8 @@ export default class UserPushAPI extends BaseAPI<
159
190
  try {
160
191
  req = req as OneUptimeRequest;
161
192
 
193
+ const userId: ObjectID = getAuthenticatedUserId(req);
194
+
162
195
  if (!req.params["deviceId"]) {
163
196
  return Response.sendErrorResponse(
164
197
  req,
@@ -192,10 +225,7 @@ export default class UserPushAPI extends BaseAPI<
192
225
  }
193
226
 
194
227
  // Check if the device belongs to the current user
195
- if (
196
- device.userId?.toString() !==
197
- (req as OneUptimeRequest).userAuthorization!.userId!.toString()
198
- ) {
228
+ if (device.userId?.toString() !== userId.toString()) {
199
229
  return Response.sendErrorResponse(
200
230
  req,
201
231
  res,
@@ -264,6 +294,8 @@ export default class UserPushAPI extends BaseAPI<
264
294
  try {
265
295
  req = req as OneUptimeRequest;
266
296
 
297
+ const userId: ObjectID = getAuthenticatedUserId(req);
298
+
267
299
  if (!req.params["deviceId"]) {
268
300
  return Response.sendErrorResponse(
269
301
  req,
@@ -279,6 +311,7 @@ export default class UserPushAPI extends BaseAPI<
279
311
  },
280
312
  select: {
281
313
  userId: true,
314
+ projectId: true,
282
315
  },
283
316
  });
284
317
 
@@ -291,10 +324,7 @@ export default class UserPushAPI extends BaseAPI<
291
324
  }
292
325
 
293
326
  // Check if the device belongs to the current user
294
- if (
295
- device.userId?.toString() !==
296
- (req as OneUptimeRequest).userAuthorization!.userId!.toString()
297
- ) {
327
+ if (device.userId?.toString() !== userId.toString()) {
298
328
  return Response.sendErrorResponse(
299
329
  req,
300
330
  res,
@@ -304,6 +334,21 @@ export default class UserPushAPI extends BaseAPI<
304
334
 
305
335
  await this.service.verifyDevice(device._id!.toString());
306
336
 
337
+ // Create default notification rules for this verified push device
338
+ try {
339
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
340
+ {
341
+ projectId: new ObjectID(device.projectId!.toString()),
342
+ userId,
343
+ notificationMethod: {
344
+ userPushId: device.id!,
345
+ },
346
+ },
347
+ );
348
+ } catch (e) {
349
+ logger.error(e);
350
+ }
351
+
307
352
  return Response.sendEmptySuccessResponse(req, res);
308
353
  } catch (error) {
309
354
  return next(error);
@@ -318,6 +363,8 @@ export default class UserPushAPI extends BaseAPI<
318
363
  try {
319
364
  req = req as OneUptimeRequest;
320
365
 
366
+ const userId: ObjectID = getAuthenticatedUserId(req);
367
+
321
368
  if (!req.params["deviceId"]) {
322
369
  return Response.sendErrorResponse(
323
370
  req,
@@ -345,10 +392,7 @@ export default class UserPushAPI extends BaseAPI<
345
392
  }
346
393
 
347
394
  // Check if the device belongs to the current user
348
- if (
349
- device.userId?.toString() !==
350
- (req as OneUptimeRequest).userAuthorization!.userId!.toString()
351
- ) {
395
+ if (device.userId?.toString() !== userId.toString()) {
352
396
  return Response.sendErrorResponse(
353
397
  req,
354
398
  res,
@@ -2,6 +2,7 @@ import UserMiddleware from "../Middleware/UserAuthorization";
2
2
  import UserSMSService, {
3
3
  Service as UserSMSServiceType,
4
4
  } from "../Services/UserSmsService";
5
+ import UserNotificationRuleService from "../Services/UserNotificationRuleService";
5
6
  import {
6
7
  ExpressRequest,
7
8
  ExpressResponse,
@@ -9,8 +10,10 @@ import {
9
10
  OneUptimeRequest,
10
11
  } from "../Utils/Express";
11
12
  import Response from "../Utils/Response";
13
+ import logger from "../Utils/Logger";
12
14
  import BaseAPI from "./BaseAPI";
13
15
  import BadDataException from "../../Types/Exception/BadDataException";
16
+ import ObjectID from "../../Types/ObjectID";
14
17
  import UserSMS from "../../Models/DatabaseModels/UserSMS";
15
18
 
16
19
  export default class UserSMSAPI extends BaseAPI<UserSMS, UserSMSServiceType> {
@@ -48,6 +51,7 @@ export default class UserSMSAPI extends BaseAPI<UserSMS, UserSMSServiceType> {
48
51
  },
49
52
  select: {
50
53
  userId: true,
54
+ projectId: true,
51
55
  verificationCode: true,
52
56
  },
53
57
  });
@@ -91,6 +95,21 @@ export default class UserSMSAPI extends BaseAPI<UserSMS, UserSMSServiceType> {
91
95
  },
92
96
  });
93
97
 
98
+ // Create default notification rules for this verified SMS
99
+ try {
100
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
101
+ {
102
+ projectId: new ObjectID(item.projectId!.toString()),
103
+ userId: new ObjectID(item.userId!.toString()),
104
+ notificationMethod: {
105
+ userSmsId: item.id!,
106
+ },
107
+ },
108
+ );
109
+ } catch (e) {
110
+ logger.error(e);
111
+ }
112
+
94
113
  return Response.sendEmptySuccessResponse(req, res);
95
114
  } catch (err) {
96
115
  return next(err);
@@ -2,6 +2,7 @@ import UserMiddleware from "../Middleware/UserAuthorization";
2
2
  import UserWhatsAppService, {
3
3
  Service as UserWhatsAppServiceType,
4
4
  } from "../Services/UserWhatsAppService";
5
+ import UserNotificationRuleService from "../Services/UserNotificationRuleService";
5
6
  import {
6
7
  ExpressRequest,
7
8
  ExpressResponse,
@@ -9,8 +10,10 @@ import {
9
10
  OneUptimeRequest,
10
11
  } from "../Utils/Express";
11
12
  import Response from "../Utils/Response";
13
+ import logger from "../Utils/Logger";
12
14
  import BaseAPI from "./BaseAPI";
13
15
  import BadDataException from "../../Types/Exception/BadDataException";
16
+ import ObjectID from "../../Types/ObjectID";
14
17
  import UserWhatsApp from "../../Models/DatabaseModels/UserWhatsApp";
15
18
 
16
19
  export default class UserWhatsAppAPI extends BaseAPI<
@@ -50,6 +53,7 @@ export default class UserWhatsAppAPI extends BaseAPI<
50
53
  },
51
54
  select: {
52
55
  userId: true,
56
+ projectId: true,
53
57
  verificationCode: true,
54
58
  isVerified: true,
55
59
  },
@@ -100,6 +104,21 @@ export default class UserWhatsAppAPI extends BaseAPI<
100
104
  },
101
105
  });
102
106
 
107
+ // Create default notification rules for this verified WhatsApp number
108
+ try {
109
+ await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
110
+ {
111
+ projectId: new ObjectID(item.projectId!.toString()),
112
+ userId: new ObjectID(item.userId!.toString()),
113
+ notificationMethod: {
114
+ userWhatsAppId: item.id!,
115
+ },
116
+ },
117
+ );
118
+ } catch (e) {
119
+ logger.error(e);
120
+ }
121
+
103
122
  return Response.sendEmptySuccessResponse(req, res);
104
123
  } catch (err) {
105
124
  return next(err);
@@ -80,4 +80,11 @@ export default class DatabaseConfig {
80
80
  "disableSignup",
81
81
  )) as boolean;
82
82
  }
83
+
84
+ @CaptureSpan()
85
+ public static async shouldDisableUserProjectCreation(): Promise<boolean> {
86
+ return (await DatabaseConfig.getFromGlobalConfig(
87
+ "disableUserProjectCreation",
88
+ )) as boolean;
89
+ }
83
90
  }
@@ -161,6 +161,14 @@ export const ClusterKey: ObjectID = new ObjectID(
161
161
 
162
162
  export const HasClusterKey: boolean = Boolean(process.env["ONEUPTIME_SECRET"]);
163
163
 
164
+ export const RegisterProbeKey: ObjectID = new ObjectID(
165
+ process.env["REGISTER_PROBE_KEY"] || "secret",
166
+ );
167
+
168
+ export const HasRegisterProbeKey: boolean = Boolean(
169
+ process.env["REGISTER_PROBE_KEY"],
170
+ );
171
+
164
172
  export const AppApiHostname: Hostname = Hostname.fromString(
165
173
  `${process.env["SERVER_APP_HOSTNAME"] || "localhost"}:${
166
174
  process.env["APP_PORT"] || 80
@@ -529,6 +537,13 @@ export const VapidPrivateKey: string | undefined =
529
537
  export const VapidSubject: string =
530
538
  process.env["VAPID_SUBJECT"] || "mailto:support@oneuptime.com";
531
539
 
540
+ export const ExpoAccessToken: string | undefined =
541
+ process.env["EXPO_ACCESS_TOKEN"] || undefined;
542
+
543
+ export const PushNotificationRelayUrl: string =
544
+ process.env["PUSH_NOTIFICATION_RELAY_URL"] ||
545
+ "https://oneuptime.com/api/notification/push-relay/send";
546
+
532
547
  export const EnterpriseLicenseValidationUrl: URL = URL.fromString(
533
548
  "https://oneuptime.com/api/enterprise-license/validate",
534
549
  );
@@ -0,0 +1,23 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class MigrationName1770834237091 implements MigrationInterface {
4
+ public name = "MigrationName1770834237091";
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(
8
+ `ALTER TABLE "GlobalConfig" ADD "disableUserProjectCreation" boolean DEFAULT false`,
9
+ );
10
+ await queryRunner.query(
11
+ `ALTER TABLE "GlobalConfig" ADD CONSTRAINT "UQ_disableUserProjectCreation" UNIQUE ("disableUserProjectCreation")`,
12
+ );
13
+ }
14
+
15
+ public async down(queryRunner: QueryRunner): Promise<void> {
16
+ await queryRunner.query(
17
+ `ALTER TABLE "GlobalConfig" DROP CONSTRAINT "UQ_disableUserProjectCreation"`,
18
+ );
19
+ await queryRunner.query(
20
+ `ALTER TABLE "GlobalConfig" DROP COLUMN "disableUserProjectCreation"`,
21
+ );
22
+ }
23
+ }
@@ -258,6 +258,7 @@ import { MigrationName1770728946893 } from "./1770728946893-MigrationName";
258
258
  import { MigrationName1770732721195 } from "./1770732721195-MigrationName";
259
259
  import { MigrationName1770833704656 } from "./1770833704656-MigrationName";
260
260
  import { MigrationName1770834237090 } from "./1770834237090-MigrationName";
261
+ import { MigrationName1770834237091 } from "./1770834237091-MigrationName";
261
262
 
262
263
  export default [
263
264
  InitialMigration,
@@ -520,4 +521,5 @@ export default [
520
521
  MigrationName1770732721195,
521
522
  MigrationName1770833704656,
522
523
  MigrationName1770834237090,
524
+ MigrationName1770834237091,
523
525
  ];
@@ -124,6 +124,7 @@ export class ProjectService extends DatabaseService<Model> {
124
124
  select: {
125
125
  name: true,
126
126
  email: true,
127
+ isMasterAdmin: true,
127
128
  companyPhoneNumber: true,
128
129
  companyName: true,
129
130
  utmCampaign: true,
@@ -142,6 +143,15 @@ export class ProjectService extends DatabaseService<Model> {
142
143
  throw new BadDataException("User not found.");
143
144
  }
144
145
 
146
+ // Check if project creation is restricted to admins only
147
+ const shouldDisableProjectCreation: boolean =
148
+ await DatabaseConfig.shouldDisableUserProjectCreation();
149
+ if (shouldDisableProjectCreation && !user.isMasterAdmin) {
150
+ throw new NotAuthorizedException(
151
+ "Project creation is restricted to admin users only on this OneUptime Server. Please contact your server admin.",
152
+ );
153
+ }
154
+
145
155
  if (IsBillingEnabled) {
146
156
  if (!data.data.paymentProviderPlanId) {
147
157
  throw new BadDataException("Plan required to create the project.");
@@ -1313,6 +1323,8 @@ export class ProjectService extends DatabaseService<Model> {
1313
1323
  paymentProviderSubscriptionId: true,
1314
1324
  paymentProviderMeteredSubscriptionId: true,
1315
1325
  name: true,
1326
+ createdAt: true,
1327
+ planName: true,
1316
1328
  createdByUser: {
1317
1329
  name: true,
1318
1330
  email: true,
@@ -1341,6 +1353,8 @@ export class ProjectService extends DatabaseService<Model> {
1341
1353
  let slackMessage: string = `*Project Deleted:*
1342
1354
  *Project Name:* ${project.name?.toString() || "N/A"}
1343
1355
  *Project ID:* ${project._id?.toString() || "N/A"}
1356
+ *Project Created Date:* ${project.createdAt ? new Date(project.createdAt).toUTCString() : "N/A"}
1357
+ *Project Plan Name:* ${project.planName?.toString() || "N/A"}
1344
1358
  `;
1345
1359
 
1346
1360
  if (subscriptionStatus) {