Compare commits

...

626 Commits

Author SHA1 Message Date
Simon Larsen
3938637b84 feat: Enhance MarkdownViewer styling and improve preformatted code handling 2025-09-10 20:08:30 +01:00
Simon Larsen
3ed9e21271 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-09-10 19:09:57 +01:00
Simon Larsen
63e1266e2b feat: Improve MarkdownViewer styling with enhanced Tailwind CSS classes for better readability and aesthetics 2025-09-10 19:09:53 +01:00
Nawaz Dhandala
a552812711 feat: Add projectId support to SlackUtil message sending for incident and scheduled maintenance actions 2025-09-10 18:21:30 +01:00
Nawaz Dhandala
ad07ab75fe feat: Add elkjs dependency for enhanced functionality 2025-09-10 18:13:59 +01:00
Nawaz Dhandala
c8deffebb0 refactor: Improve code readability by standardizing formatting and spacing in SlackUtil methods 2025-09-10 17:12:51 +01:00
Simon Larsen
67a3ea5109 feat: Enhance SlackUtil with projectId support and caching for channel operations 2025-09-10 17:11:04 +01:00
Simon Larsen
6728cc0458 feat: Add projectId parameter to channel-related methods for improved context handling 2025-09-10 17:08:02 +01:00
Simon Larsen
f84ab2474f feat: Optimize channel existence checks by introducing getWorkspaceChannelByName method and streamline channel name normalization 2025-09-10 16:47:36 +01:00
Simon Larsen
5c8ce04eed feat: Enhance pagination handling by supporting 'skip' and 'limit' parameters from both query and body 2025-09-09 16:56:55 +01:00
Nawaz Dhandala
3064aa0364 feat: Improve code formatting and descriptions in announcement-related components and migrations for better readability 2025-09-09 14:36:32 +01:00
Simon Larsen
9625f1381c feat: Add migration for AnnouncementMonitor and AnnouncementTemplateMonitor tables with foreign key constraints 2025-09-09 14:12:33 +01:00
Simon Larsen
6ecd3ad166 Merge branch 'master' into announcement-monitor 2025-09-09 14:04:36 +01:00
Simon Larsen
8e54cac86e feat: Add createEditModalWidth prop with large size to multiple template views for consistent modal presentation 2025-09-09 14:01:46 +01:00
Nawaz Dhandala
cc52bb76d1 feat: Enhance incident state handling by adding type definitions, improving error handling, and updating default state display 2025-09-09 13:54:52 +01:00
Nawaz Dhandala
4c037f54f4 feat: Refactor incident state migration and update related components for improved clarity and functionality 2025-09-09 13:49:34 +01:00
Simon Larsen
b869628d4a feat: Implement fetch for initial incident state and update form values 2025-09-09 13:48:11 +01:00
Simon Larsen
0fbeb503ad feat: Update incident state field title and description for clarity 2025-09-09 13:06:29 +01:00
Simon Larsen
a302e4dc6c feat: Implement automatic selection of the first incident state and update related references 2025-09-09 12:58:07 +01:00
Nawaz Dhandala
00c8783137 feat: Add monitor selection to status page announcements and templates, enhancing resource notification capabilities 2025-09-09 12:56:42 +01:00
Simon Larsen
11211f4a62 feat: Update initial incident state description to reflect default behavior 2025-09-09 12:53:30 +01:00
Simon Larsen
d29750d66e feat: Add initialIncidentState field to IncidentTemplates for incident creation 2025-09-09 12:47:15 +01:00
Simon Larsen
7dc590dab4 feat: Add initialIncidentStateId migration and update index references 2025-09-09 12:37:43 +01:00
Simon Larsen
1d0ed64c1a feat: Rename currentIncidentState to initialIncidentState and update related references in IncidentTemplate, IncidentService, and IncidentTemplatesView 2025-09-09 12:26:48 +01:00
Simon Larsen
0cf3884be4 Merge branch 'master' into select-incident-state 2025-09-09 12:21:12 +01:00
Simon Larsen
165f5608e6 feat: Add step to free disk space in GitHub Actions runner for improved image build efficiency 2025-09-09 12:18:07 +01:00
Nawaz Dhandala
f2b8cfbffb Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-09-09 12:12:57 +01:00
Nawaz Dhandala
6084e15f20 refactor: Enhance type annotations in MarkdownEditor and tests for improved type safety 2025-09-09 12:12:55 +01:00
Simon Larsen
b1db4187de Learn more about Markdown syntax. 2025-09-09 12:12:09 +01:00
Nawaz Dhandala
20ce8a8c74 refactor: Clean up MarkdownEditor and FormField code for improved readability and consistency 2025-09-09 11:45:00 +01:00
Simon Larsen
39200249d1 feat: Update spell check handling in MarkdownEditor and tests for improved functionality 2025-09-09 11:38:58 +01:00
Simon Larsen
27533125e4 feat: Add createEditModalWidth prop to multiple components for consistent modal sizing 2025-09-09 11:23:20 +01:00
Simon Larsen
99dd421329 feat: Add createEditModalWidth prop to IncidentDelete for consistent modal sizing 2025-09-09 11:17:11 +01:00
Simon Larsen
4184894f27 feat: Refactor MarkdownEditor toolbar layout for improved organization and readability 2025-09-09 11:12:40 +01:00
Simon Larsen
a7a00dc0fa feat: Add dataTestId prop to MarkdownEditor and FormField for improved testing 2025-09-09 10:58:06 +01:00
Simon Larsen
9340f69789 feat: Add additional toolbar buttons and formatting options in MarkdownEditor 2025-09-09 10:35:10 +01:00
Simon Larsen
ba33bc0c23 feat: Enhance MarkdownEditor with improved heading handling and toolbar buttons 2025-09-09 10:27:41 +01:00
Simon Larsen
b8cac60c6e feat: Enhance Markdown preview with improved code block handling and styling 2025-09-09 09:59:32 +01:00
Simon Larsen
3a5d5253d0 feat: Enhance MarkdownEditor with toolbar buttons and preview functionality 2025-09-09 09:53:44 +01:00
Simon Larsen
64010b0348 feat: Add initial incident state selection to incident templates and creation forms 2025-09-09 08:35:46 +01:00
Simon Larsen
84ca2ff311 fix: Remove redundant APP_VERSION build argument in Docker image deployment steps 2025-09-08 22:08:00 +01:00
Simon Larsen
c0becebadc feat: Update date formatting to user-friendly display in getMonitorStatusTimelineForStatusPage method 2025-09-08 21:58:53 +01:00
Nawaz Dhandala
6ef99fd890 refactor: Specify types for format and testDate in OneUptimeDate class methods 2025-09-08 21:52:31 +01:00
Nawaz Dhandala
a55f2f7842 refactor: Improve code readability by formatting function arguments and return values in date handling methods 2025-09-08 21:51:53 +01:00
Simon Larsen
0aae7877c7 feat: Update date formatting to user-friendly display in various components 2025-09-08 21:49:19 +01:00
Simon Larsen
8d6cc37f7a feat: Update date formatting to user-friendly display across various components 2025-09-08 21:41:57 +01:00
Simon Larsen
1a0f7eb1e7 feat: Enhance date formatting to user-friendly display in Scheduled Maintenance components 2025-09-08 21:36:47 +01:00
Simon Larsen
6ed65ed3ef fix: Change tag type from semver to raw for Docker image deployments 2025-09-08 20:43:09 +01:00
Simon Larsen
2ac342e26a feat: Add billing_enabled variable to Nginx configuration 2025-09-08 20:29:28 +01:00
Simon Larsen
fe80d6b1ff fix: Remove unnecessary markdown syntax from upgrading guide 2025-09-08 18:44:43 +01:00
Simon Larsen
a68254be6d fix: Clarify reason for discontinuing Bitnami charts in upgrading guide 2025-09-08 18:43:14 +01:00
Simon Larsen
49a9e355fe feat: Add upgrading guide and navigation link to documentation 2025-09-08 18:41:40 +01:00
Simon Larsen
7091e35393 Update GitHub Actions workflow to read version prefix from VERSION_PREFIX file and adjust versioning scheme
- Added a new job 'read-version' to read the major and minor version from VERSION_PREFIX file.
- Updated dependent jobs to use the version read from 'read-version' instead of hardcoded version.
- Changed versioning format in multiple jobs to reflect the new versioning scheme based on the content of VERSION_PREFIX.
- Created VERSION_PREFIX file with initial version set to 8.0.
2025-09-07 15:17:47 +01:00
Simon Larsen
34cc8a43ab Merge pull request #1995 from OneUptime/bitnami-mgr-postgres
Bitnami mgr postgres
2025-09-07 13:21:41 +01:00
Simon Larsen
75333ef36c feat: Add pod security context configuration for ClickHouse and Redis StatefulSets 2025-09-07 13:03:09 +01:00
Simon Larsen
d4b3f1b60b feat: Add primary pod security context configuration for PostgreSQL 2025-09-07 12:59:27 +01:00
Simon Larsen
318d20a5a5 feat: Update PostgreSQL StatefulSet to use primary nodeSelector, affinity, tolerations, and resources 2025-09-07 12:56:29 +01:00
Simon Larsen
44b9c33e5c feat: Add primary ConfigMaps for PostgreSQL configuration and pg_hba settings 2025-09-07 12:45:32 +01:00
Simon Larsen
317a17cbab feat: Rename PostgreSQL ConfigMaps to include 'primary' in their names for clarity 2025-09-07 12:40:23 +01:00
Simon Larsen
6d2cb53760 feat: Update PostgreSQL configuration to use primary settings for ConfigMaps 2025-09-07 12:37:30 +01:00
Simon Larsen
7ddc4be319 feat: Add pg_hba.conf configuration and corresponding ConfigMap for PostgreSQL 2025-09-07 12:32:47 +01:00
Simon Larsen
604776551b feat: Add PostgreSQL configuration checksum and update container args 2025-09-07 12:25:41 +01:00
Simon Larsen
26b085030d refactor: Remove initContainers from PostgreSQL StatefulSet and enable default configuration settings 2025-09-07 12:17:13 +01:00
Simon Larsen
e1046d2424 Merge branch 'master' into bitnami-mgr-postgres 2025-09-07 11:08:46 +01:00
Simon Larsen
cf2a7b9dfa feat: Enhance diagnostics collection in KinD setup script 2025-09-07 11:05:34 +01:00
Simon Larsen
55f4c0b65d docs: Add SQL query to check used and free space in Postgres 2025-09-06 20:38:34 +01:00
Simon Larsen
5100fbda52 docs: Add SQL query to check used and free space in Clickhouse 2025-09-06 20:35:17 +01:00
Simon Larsen
9e36188975 fix: Update image registry and repository in ci-values.yaml 2025-09-06 17:47:47 +01:00
Simon Larsen
26c2d41dfa Merge branch 'master' into bitnami-mgr-postgres 2025-09-06 17:45:00 +01:00
Simon Larsen
a511a433b1 refactor: Remove security context and default profiles from ClickHouse configuration 2025-09-06 11:27:50 +01:00
Simon Larsen
cc581e91b5 Merge pull request #1994 from OneUptime/bitnami-mgr
Bitnami mgr
2025-09-06 11:09:13 +01:00
Simon Larsen
3fd95fe8aa Merge branch 'master' into bitnami-mgr 2025-09-06 11:09:01 +01:00
Simon Larsen
6f2455c265 fix: Set ClickHouse resourcesPreset to "none" to override default value 2025-09-05 21:26:00 +01:00
Simon Larsen
de5b32a609 refactor: Remove default resourcesPreset for ClickHouse configuration 2025-09-05 21:17:13 +01:00
Simon Larsen
155b0d90f1 refactor: Transition from MicroK8s to KinD for Kubernetes cluster setup in CI scripts 2025-09-05 21:15:58 +01:00
Simon Larsen
3da5e12a0d feat: Add auto-generated password option for ClickHouse configuration 2025-09-05 21:14:58 +01:00
Simon Larsen
8accdc6bd4 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-09-05 20:56:35 +01:00
Simon Larsen
22a10702ac feat: Add comprehensive architecture diagram and explanation for self-hosted setup 2025-09-05 20:56:32 +01:00
Nawaz Dhandala
a013c86fae refactor: Standardize wait duration for pod readiness checks 2025-09-05 16:24:25 +01:00
Nawaz Dhandala
361626d21f refactor: Enhance pod readiness check with improved diagnostics and error handling 2025-09-05 16:23:01 +01:00
Simon Larsen
6615ac63d7 refactor: Simplify legal page structure and enhance navigation with Bootstrap styling 2025-09-05 14:50:22 +01:00
Simon Larsen
655611b28d refactor: Revamp support page layout and content for improved user experience 2025-09-05 14:45:55 +01:00
Simon Larsen
9bd45ecd14 Merge branch 'master' into bitnami-mgr-postgres 2025-09-05 14:01:46 +01:00
Simon Larsen
53c9babb83 refactor: Replace commented wait logic with active polling for pod readiness 2025-09-05 14:01:00 +01:00
Simon Larsen
ccc0b0142b feat: Remove default profiles configuration from ClickHouse settings in values.yaml 2025-09-05 13:51:07 +01:00
Simon Larsen
4a2f7f68cb feat: Update PostgreSQL password field to use 'postgresPassword' in values.yaml and secrets.yaml 2025-09-05 12:48:10 +01:00
Simon Larsen
de994e10de feat: Fix PostgreSQL username to be fixed as "postgres" in values.yaml 2025-09-05 12:21:43 +01:00
Simon Larsen
2ff22ca079 feat: Enhance security context handling for ClickHouse, PostgreSQL, and Redis StatefulSets 2025-09-05 12:06:28 +01:00
Simon Larsen
e6b8f60977 feat: Update security context for init and primary PostgreSQL containers 2025-09-05 11:59:37 +01:00
Simon Larsen
b823b5924a feat: Add init container for PostgreSQL configuration symlinks and update security context 2025-09-05 11:42:35 +01:00
Simon Larsen
a58ddd94d5 feat: Add POSTGRES_INITDB_ARGS environment variable for PostgreSQL initialization 2025-09-04 20:19:08 +01:00
Simon Larsen
275e15ce96 feat: Update PostgreSQL environment variables and liveness probe configuration 2025-09-04 20:12:20 +01:00
Simon Larsen
1e2a30823c feat: Remove PostgreSQL authentication environment variables from StatefulSet 2025-09-04 19:48:21 +01:00
Simon Larsen
a326e7084e feat: Remove PostgreSQL dependency and associated chart from Helm configuration 2025-09-04 17:55:18 +01:00
Simon Larsen
2c1d20f680 feat: Remove PostgreSQL dependency from Helm chart 2025-09-04 17:54:48 +01:00
Simon Larsen
95bd2db0dd feat: Add security context support for ClickHouse, PostgreSQL, and Redis StatefulSets 2025-09-04 17:44:59 +01:00
Simon Larsen
3ca875254c feat: Add PostgreSQL StatefulSet configuration to Helm chart 2025-09-04 17:35:39 +01:00
Simon Larsen
7f1f78dad6 feat: Add PostgreSQL Secret configuration to Helm chart 2025-09-04 17:27:49 +01:00
Simon Larsen
a0d6468aee feat: Add PostgreSQL ConfigMap and Service templates for Helm chart 2025-09-04 17:27:30 +01:00
Simon Larsen
914c9bc58e feat: Update PostgreSQL configuration in values.yaml and README for built-in support 2025-09-04 17:26:21 +01:00
Simon Larsen
b38031e9f7 feat: Add subPath for data and config mounts in ClickHouse StatefulSet 2025-09-04 17:03:57 +01:00
Simon Larsen
487ca71f84 fix: Rename volume and mount paths for Redis data in StatefulSet configuration 2025-09-04 15:30:27 +01:00
Simon Larsen
67cd8e7db6 refactor: Remove initContainers from ClickHouse StatefulSet configuration 2025-09-04 15:28:17 +01:00
Simon Larsen
f44017d710 feat: Add Helm annotations for release name and namespace in templates 2025-09-04 12:23:16 +01:00
Simon Larsen
78240b906b feat: Add ClickHouse StatefulSet configuration to Helm chart 2025-09-03 21:57:59 +01:00
Simon Larsen
2ef0b3be27 feat: Add ClickHouse ConfigMap template for configuration management 2025-09-03 21:43:20 +01:00
Simon Larsen
0792d8367a feat: Add ClickHouse service and secret configurations to Helm chart 2025-09-03 21:43:01 +01:00
Simon Larsen
920397cead fix: Remove ClickHouse chart package from the repository 2025-09-03 21:41:35 +01:00
Simon Larsen
42c18e94ab feat: Update ClickHouse configuration and service settings in values.yaml 2025-09-03 21:41:29 +01:00
Simon Larsen
533f7eb238 fix: Remove ClickHouse dependency from Chart.yaml and Chart.lock 2025-09-03 21:38:03 +01:00
Simon Larsen
e2f16e85f1 Merge pull request #1993 from OneUptime/bitnami-mgr
Bitnami mgr
2025-09-03 20:12:22 +01:00
Simon Larsen
c98e6b8471 feat: Add KEDA chart dependency to README 2025-09-03 20:12:09 +01:00
Simon Larsen
c16c13fd89 feat: Add built-in Redis configuration to README and update external Redis instructions 2025-09-03 20:10:43 +01:00
Simon Larsen
c8ce0e8819 fix: Remove Redis cluster configuration options from values.yaml 2025-09-03 20:00:14 +01:00
Simon Larsen
9e98f6acdb fix: Remove Redis replica persistence configuration from values.yaml 2025-09-03 19:50:07 +01:00
Simon Larsen
a7a5b15dde feat: Implement Redis StatefulSet configuration in Helm chart 2025-09-03 19:49:49 +01:00
Simon Larsen
3ebb5217a2 feat: Add Redis master and headless service definitions to Helm chart 2025-09-03 19:46:10 +01:00
Simon Larsen
f570ffe1e3 feat: Add Redis ConfigMap template to Helm chart for Redis configuration management 2025-09-03 19:43:57 +01:00
Simon Larsen
ae94bf6d7c fix: Simplify Redis password handling in Helm chart by removing unnecessary conditional checks 2025-09-03 19:42:28 +01:00
Simon Larsen
d9a6e465bb fix: Remove Redis authentication requirement in values.yaml 2025-09-03 19:42:11 +01:00
Simon Larsen
020b171b77 fix: Update Redis password handling in Helm chart to support optional authentication 2025-09-03 19:38:06 +01:00
Simon Larsen
afc4932c28 fix: Remove Redis dependency and related configurations from Helm chart 2025-09-03 19:37:30 +01:00
Nawaz Dhandala
324851c57e fix: Refactor service operations to execute sequentially with improved error handling in AlertService, IncidentService, MonitorService, and ScheduledMaintenanceService 2025-09-03 15:41:23 +01:00
Nawaz Dhandala
380ecfa096 Refactor code for consistency and readability
- Updated array and object property access from single quotes to double quotes in Pagination.ts and Permissions.ts for consistency.
- Added missing commas in function parameters and object literals across multiple files in AlertService.ts, IncidentService.ts, MonitorService.ts, ScheduledMaintenanceService.ts, and WorkspaceNotificationRuleService.ts.
- Improved error logging messages in various services for better clarity.
- Removed unnecessary line breaks in Slack.ts and Workspace.ts for cleaner code.
- Ensured consistent formatting in Routes.ts by adding missing commas and adjusting line breaks.
2025-09-03 15:37:39 +01:00
Simon Larsen
5f9f73ceaa fix: Refactor monitor creation operations to execute sequentially with improved error handling in MonitorService 2025-09-03 15:35:13 +01:00
Simon Larsen
038ca4a920 fix: Update imports and improve formatting in Routes.ts for consistency and readability 2025-09-03 15:34:29 +01:00
Simon Larsen
d15629da0f fix: Refactor scheduled maintenance operations to execute sequentially with improved error handling in ScheduledMaintenanceService 2025-09-03 15:21:03 +01:00
Simon Larsen
363bbf9dea fix: Refactor incident creation operations to execute sequentially with improved error handling in IncidentService 2025-09-03 15:17:16 +01:00
Simon Larsen
6f0a0c8e38 fix: Remove unnecessary line breaks in error messages and logging for improved readability in WorkspaceNotificationRuleService 2025-09-03 15:06:19 +01:00
Simon Larsen
a75a62c708 fix: Refactor promise chain to use async/await for better readability in AlertService; add debug logging in WorkspaceNotificationRuleService 2025-09-03 14:18:05 +01:00
Simon Larsen
db76d716b9 fix: Remove redundant logging of existing workspace channels for cleaner output 2025-09-03 14:02:12 +01:00
Simon Larsen
b0abbf64b4 fix: Improve logging format in postToWorkspaceChannels for better readability 2025-09-03 13:55:43 +01:00
Simon Larsen
3a432cf8e6 Response from Slack API for getting all channels: 2025-09-03 13:54:58 +01:00
Simon Larsen
5c7d18e3ed fix: Update createdByUser field to use _id for consistency in Alert, Incident, and Scheduled Maintenance services 2025-09-03 13:27:37 +01:00
Simon Larsen
2590850ffa fix: Correct projectId usage in alert feed info generation for accurate monitor links 2025-09-03 13:13:14 +01:00
Simon Larsen
0eeb80e16e fix: Add createdByUserId and createdByUser fields to alert, incident, and scheduled maintenance services for improved tracking 2025-09-03 13:09:38 +01:00
Simon Larsen
e1cfe24a24 fix: Update pageData property access to bracket notation for consistency 2025-09-02 22:59:23 +01:00
Simon Larsen
4e4f3a889d fix: Update type casting for statusReport and probeMonitorResponse to 'any' for improved flexibility 2025-09-02 22:51:41 +01:00
Nawaz Dhandala
ede7ae103d fix: Enhance MonitorTemplateUtil to support additional monitor types and improve type safety 2025-09-02 22:15:04 +01:00
Simon Larsen
075c0fb6bd fix: Enhance template variable support for additional monitor types in MonitorTemplateUtil and update documentation 2025-09-02 22:08:51 +01:00
Nawaz Dhandala
5ebdb1ef7d fix: Refactor code for improved readability and maintainability in various components 2025-09-02 21:57:15 +01:00
Simon Larsen
387dbf332e fix: Correct spelling in API endpoint routes for escalation rules 2025-09-02 21:48:54 +01:00
Simon Larsen
9681e1dc88 fix: Remove fallback syntax from incident alert templating examples for clarity 2025-09-02 21:47:05 +01:00
Simon Larsen
fb29014480 Merge branch 'dynamic-alert' 2025-09-02 21:45:15 +01:00
Simon Larsen
1a5c2efc59 fix: Add debug logging for storage map and template value replacement in MonitorTemplateUtil 2025-09-02 21:43:28 +01:00
Simon Larsen
3e31e44ed5 fix: Enhance value replacement logic to properly serialize objects in VMUtil class 2025-09-02 21:26:55 +01:00
Simon Larsen
9e69d69429 fix: Update titles and descriptions for Global Probes settings for clarity 2025-09-02 21:15:21 +01:00
Simon Larsen
a108deac0f fix: Improve documentation links in MonitorCriteriaAlertForm and MonitorCriteriaIncidentForm for clarity 2025-09-02 21:14:03 +01:00
Simon Larsen
c767f14bf1 fix: Correct syntax error in AlertService class 2025-09-02 21:11:28 +01:00
Simon Larsen
d69485c436 fix: Update Global Probes status messages for clarity in ProbePage component 2025-09-02 20:50:20 +01:00
Simon Larsen
67a5bdb7b8 feat: Update Global Probe settings card with improved descriptions and toggle functionality 2025-09-02 20:47:56 +01:00
Nawaz Dhandala
6504731025 refactor: Replace 'any' types with specific types for improved type safety across multiple files 2025-09-02 20:41:24 +01:00
Nawaz Dhandala
773692081c docs: Update guideline to specify stopping after fixing 25 files for review 2025-09-02 20:25:52 +01:00
Nawaz Dhandala
51c6234966 docs: Add guideline to replace "any" types with proper types 2025-09-02 20:23:53 +01:00
Nawaz Dhandala
fac6e9a1fe fix: Correct formatting issues in MonitorTemplateUtil and MonitorCriteriaAlertForm 2025-09-02 20:14:33 +01:00
Nawaz Dhandala
86e5d85d55 feat: Enhance dynamic template documentation links in MonitorCriteriaAlertForm and MonitorCriteriaIncidentForm 2025-09-02 20:10:14 +01:00
Simon Larsen
1c592435e9 Merge pull request #1990 from OneUptime/any-type
Any type
2025-09-02 20:02:38 +01:00
Nawaz Dhandala
02fed5bd6e refactor: Enhance type safety by explicitly defining ref types and simplifying conditional checks 2025-09-02 19:58:41 +01:00
Nawaz Dhandala
dd724fcc6e refactor: Improve type safety by updating formRef initialization and adding optional chaining for setFieldValue 2025-09-02 19:52:28 +01:00
Nawaz Dhandala
6ba26bcb82 refactor: Improve type safety by adding LayoutOptions type and removing 'any' casts in ServiceDependencyGraph 2025-09-02 19:51:45 +01:00
Nawaz Dhandala
799ab3220d refactor: Replace 'any' type with specific types for ref and input for improved type safety 2025-09-02 19:50:53 +01:00
Nawaz Dhandala
f73f2fb732 refactor: Change argValue type from any to unknown for better type safety 2025-09-02 19:50:34 +01:00
Simon Larsen
43d6ead92c fix: Correct formatting issues in MonitorAlert class logging and data processing 2025-09-02 19:22:31 +01:00
Simon Larsen
4c053b3f31 refactor: Improve formatting and readability in MonitorTemplateUtil methods 2025-09-02 19:02:29 +01:00
Simon Larsen
c026e411cf feat: Add dynamic template usage descriptions in MonitorCriteriaAlertForm and MonitorCriteriaIncidentForm 2025-09-02 19:01:22 +01:00
Simon Larsen
65a9e32db1 feat: Implement MonitorTemplateUtil for dynamic template processing in incidents and alerts 2025-09-02 18:58:15 +01:00
Simon Larsen
0b15e97e08 feat: Integrate MonitorTemplateUtil for dynamic alert and incident title/description processing 2025-09-02 18:56:19 +01:00
Simon Larsen
bd74b96596 feat: Add link to Incident & Alert Dynamic Templating documentation in navigation 2025-09-02 18:45:48 +01:00
Nawaz Dhandala
990d3ea750 feat: Add doNotAddGlobalProbesByDefaultOnNewMonitors column to Project table and update related files 2025-09-02 14:59:23 +01:00
Simon Larsen
30665a1907 feat: Add migration to introduce doNotAddGlobalProbesByDefaultOnNewMonitors column in Project table 2025-09-02 14:58:09 +01:00
Simon Larsen
04db4289fa feat: Add setting to control auto-adding of global probes to new monitors 2025-09-02 14:57:18 +01:00
Nawaz Dhandala
01f4c030a7 style: Format allowedDomains and homeUrl for improved readability 2025-09-02 14:29:17 +01:00
Simon Larsen
d060ed8b64 feat: Add dynamic robots.txt route to control indexing based on domain 2025-09-02 14:27:40 +01:00
Nawaz Dhandala
413240733e fix: Remove unnecessary blank lines in Markdown and Probe initialization files 2025-09-02 14:17:15 +01:00
Simon Larsen
b0799093dd feat: Enhance proxy agent support by specifying types for httpAgent and httpsAgent in WebsiteRequest and API classes 2025-09-02 14:10:42 +01:00
Simon Larsen
0ecdc775db feat: Refactor proxy configuration to use getRequestProxyAgents method across multiple modules 2025-09-02 14:02:40 +01:00
Simon Larsen
82065c20b1 feat: Add HTTP/HTTPS proxy support in FetchMonitorTest, FetchList, and Alive jobs 2025-09-02 13:58:15 +01:00
Simon Larsen
3dcd1ee604 feat: Add HTTP/HTTPS proxy support in probeMonitorTest and probeMonitor methods 2025-09-02 13:53:57 +01:00
Simon Larsen
f63c69e6a6 feat: Add per-request HTTP/HTTPS proxy agent support in API and WebsiteRequest classes 2025-09-02 13:52:25 +01:00
Simon Larsen
6ba793e871 refactor: Remove axios proxy configuration from ProxyConfig class 2025-09-02 13:49:58 +01:00
Simon Larsen
7afd243992 feat: Remove backticks from inline code rendering in Markdown 2025-09-01 21:19:39 +01:00
Simon Larsen
4f58155719 feat: Enhance inline code rendering by removing backticks from code content 2025-09-01 21:12:30 +01:00
Simon Larsen
553adc4aef feat: Add custom styling for inline code in Markdown renderer 2025-09-01 21:11:37 +01:00
Simon Larsen
f668a626d7 refactor: Simplify code block styling in Markdown renderer 2025-09-01 21:02:19 +01:00
Nawaz Dhandala
e3bd534295 refactor: Add missing commas in logging statements for SCIM and StatusPageSCIM 2025-09-01 20:50:53 +01:00
Simon Larsen
6aa5c3b314 feat: Enhance SCIM Users endpoint to support filtering by email and improve logging 2025-09-01 20:50:12 +01:00
Simon Larsen
3bc4f7267d refactor: Clean up logging statements and remove unnecessary commas in SCIM.ts 2025-09-01 20:48:54 +01:00
Simon Larsen
a7021cf045 refactor: Replace logSCIMOperation with logger.debug for consistent logging in SCIM and StatusPageSCIM 2025-09-01 20:40:27 +01:00
Simon Larsen
2709e1d976 feat: Update values.yaml to allow insecure images temporarily and specify legacy image repositories for PostgreSQL, ClickHouse, and Redis 2025-09-01 16:38:56 +01:00
Nawaz Dhandala
8ec9d2a930 feat: Add type annotations for proxy-related variables in ProxyConfig and monitors 2025-09-01 14:58:33 +01:00
Nawaz Dhandala
224c225789 Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-09-01 14:53:33 +01:00
Simon Larsen
85dae7a307 feat: Add proxy configuration options for probes in values.yaml and update README and probe.yaml 2025-09-01 14:53:24 +01:00
Nawaz Dhandala
332a479c22 feat: Improve proxy configuration handling and logging in monitors 2025-09-01 14:50:52 +01:00
Simon Larsen
d708fbbb52 feat: Add proxy configuration examples to Custom Probe documentation and component 2025-09-01 14:49:40 +01:00
Simon Larsen
03bceb959e feat: Enhance proxy support in SSL and Synthetic Monitors to prefer HTTPS, fallback to HTTP 2025-09-01 14:47:01 +01:00
Simon Larsen
efa411206e feat: Update SSL and Synthetic Monitors to use HTTPS proxy configuration 2025-09-01 14:41:57 +01:00
Simon Larsen
27fd99f2e8 feat: Update proxy configuration to support separate HTTP and HTTPS proxy URLs 2025-09-01 14:40:54 +01:00
Simon Larsen
07361bfeb7 feat: Enhance SyntheticMonitor with proxy support in browser launch options 2025-09-01 14:07:15 +01:00
Simon Larsen
bc8a5be0fa feat: Add proxy support for CustomCodeMonitor and SyntheticMonitor with logging 2025-09-01 14:00:55 +01:00
Simon Larsen
518768078a feat: Implement proxy configuration for HTTP requests and add ProxyConfig utility 2025-09-01 13:56:29 +01:00
Simon Larsen
86e95f99ff feat: Add PROXY_URL configuration option for probe and update example env file 2025-09-01 12:52:50 +01:00
Simon Larsen
ea48f56097 feat: Add custom styles for code blocks in blog posts 2025-09-01 12:43:03 +01:00
Nawaz Dhandala
b8b9dd859a Refactor migration files for consistency and readability; update BillingService and ProjectService for improved code clarity; enhance Countries interface formatting; standardize string quotes in various components; fix minor formatting issues in Settings and SendAnnouncementCreatedNotification. 2025-08-27 14:50:48 +01:00
Simon Larsen
d28c14ef24 feat: Update projectId reference in status page notification logic 2025-08-27 14:49:33 +01:00
Simon Larsen
670bec2a12 feat: Validate projectId and statusPageId in getStatusPageLinkInDashboard method 2025-08-27 14:48:40 +01:00
Simon Larsen
aff24845a8 feat: Add financeAccountingEmail handling in updateCustomerBusinessDetails method 2025-08-27 14:26:59 +01:00
Simon Larsen
f280e97c1b feat: Add migration for financeAccountingEmail field in Project model 2025-08-27 14:14:02 +01:00
Simon Larsen
62facf62dd feat: Add financeAccountingEmail field to Project model and update billing settings 2025-08-27 14:12:16 +01:00
Simon Larsen
db0387d81a feat: Update placeholder condition to include empty string check 2025-08-27 14:06:33 +01:00
Simon Larsen
5c4b19ab3d feat: Update nodemon configurations to improve performance and debugging options 2025-08-27 13:41:05 +01:00
Simon Larsen
463755fa4d This will be synced to Stripe and appear on future invoices. 2025-08-27 13:40:26 +01:00
Simon Larsen
85888572de feat: Update subscriber notification statuses to 'Success' for existing records in Incident and related tables 2025-08-27 13:20:07 +01:00
Simon Larsen
475bb25b2d feat: Add businessDetailsCountry field to Project migration and update index 2025-08-27 13:14:40 +01:00
Simon Larsen
badd200aed feat: Add country selection dropdown for billing details and implement country options 2025-08-27 13:14:01 +01:00
Simon Larsen
b40d87cbc9 feat: Add business details country field to Project model and update billing services to handle country code 2025-08-27 13:05:54 +01:00
Simon Larsen
36d0066b3a refactor: Simplify migration by removing unnecessary constraints and columns from Project and GlobalConfig tables 2025-08-27 13:03:01 +01:00
Simon Larsen
a49a0b2cba fix: Ensure blog post cards maintain full height for consistent layout 2025-08-27 12:48:41 +01:00
Simon Larsen
bada97d474 feat: Enhance customer address handling in Stripe by mapping business details to structured address fields 2025-08-27 12:42:17 +01:00
Simon Larsen
a1699f2d55 feat: Add business details field to Project model and update Stripe customer details 2025-08-27 12:37:09 +01:00
Simon Larsen
a11e054291 feat: Add custom link rendering with Tailwind styles and external link handling 2025-08-27 11:19:20 +01:00
Simon Larsen
47cf7ba763 fix: Increase timeout for SSL provisioning and delete old data jobs to accommodate longer processing times 2025-08-27 10:16:35 +01:00
Nawaz Dhandala
4e0dfb3664 fix: Simplify BadDataException handling for disabled and missing monitors in ingestion processes 2025-08-27 10:12:13 +01:00
Simon Larsen
250cb9e547 fix: Gracefully handle expected BadDataException cases for disabled and missing monitors in probe ingestion 2025-08-27 10:10:59 +01:00
Simon Larsen
541257e3c6 fix: Handle expected BadDataException cases for disabled and missing monitors in server monitor ingestion 2025-08-27 10:10:23 +01:00
Simon Larsen
ed43686736 fix: Centralize "Monitor disabled" message and improve error handling for disabled monitors 2025-08-27 10:09:26 +01:00
Simon Larsen
9ca45f23e3 fix: Replace hardcoded "Monitor not found" messages with centralized exception messages 2025-08-27 09:58:34 +01:00
Simon Larsen
e3573a9b77 fix: Refactor monitor not found error handling to use centralized exception messages 2025-08-27 09:55:19 +01:00
Simon Larsen
c9e78044e6 fix: Improve error handling in incoming request ingestion worker to handle disabled monitors gracefully 2025-08-27 09:48:54 +01:00
Nawaz Dhandala
813581dec5 fix: Add return type to logoutUser method and specify type for route in navigateToLoginPage method 2025-08-26 21:39:35 +01:00
Nawaz Dhandala
e528decf73 fix: Refactor QueueWorker options handling; improve logoutUser method formatting and navigation logic in StatusPageUtil 2025-08-26 21:36:56 +01:00
Simon Larsen
42ef41ede8 fix: Enhance QueueWorker options with lock duration and max stalled count; improve telemetry processing with yielding to avoid stall detection 2025-08-26 21:32:38 +01:00
Simon Larsen
af26472db4 fix: Simplify email validation logic and improve user lookup in SCIM user operations 2025-08-26 21:24:39 +01:00
Simon Larsen
44b5c8b668 fix: Enhance email validation and logging in SCIM user operations 2025-08-26 20:47:50 +01:00
Simon Larsen
d821b88ed7 fix: Update Docker image tags and labels for multiple services in release workflow 2025-08-26 18:52:15 +01:00
Simon Larsen
1df43e21ff fix: Refactor logoutUser method and enhance navigation logging in StatusPageUtil 2025-08-26 18:37:49 +01:00
Simon Larsen
76ca6ee7e1 fix: Add missing continuation for APP_VERSION build argument in multiple Docker image deploy jobs 2025-08-26 18:25:32 +01:00
Simon Larsen
dac731a57b refactor: Remove unused mock for ProjectUserService in TeamMemberService tests 2025-08-26 16:56:52 +01:00
Simon Larsen
0f4b248598 fix: Add missing context for Docker image build in nginx deployment 2025-08-26 16:53:25 +01:00
Simon Larsen
b2c14e0380 fix: Add missing build context for multiple Docker image deploy jobs 2025-08-26 16:51:51 +01:00
Simon Larsen
3ab9705bbe fix: Allow deletion of teams in Users component by setting isDeleteable to true 2025-08-26 16:34:19 +01:00
Nawaz Dhandala
40812c8749 refactor: Clean up whitespace in TeamMemberService and SCIM files; update description formatting in Users component 2025-08-26 15:59:22 +01:00
Simon Larsen
45ae1501f2 refactor: Replace ProjectUser with TeamMember in SCIM query for team members 2025-08-26 15:55:23 +01:00
Simon Larsen
13d9f19606 refactor: Remove ProjectUserService calls to streamline TeamMemberService operations 2025-08-26 15:52:28 +01:00
Simon Larsen
ad3221310a refactor: Remove ProjectUser model and associated service to streamline user management 2025-08-26 15:51:06 +01:00
Simon Larsen
659042fcfb fix: Update isCreateable property to false for Teams component 2025-08-26 14:43:54 +01:00
Simon Larsen
d65b9c7b29 feat: Refactor Teams component to use TeamMember model and update filtering logic 2025-08-26 14:42:14 +01:00
Simon Larsen
dc77206e6f feat: Add debug logging for SCIM team operations to track user additions 2025-08-26 14:25:31 +01:00
Nawaz Dhandala
9c1910d3f1 refactor: Remove unnecessary context argument from Docker build commands in workflows 2025-08-26 14:09:31 +01:00
Nawaz Dhandala
afe8f8e6f4 refactor: Implement retry mechanism for account and isolated VM compilation steps in workflows 2025-08-26 13:15:54 +01:00
Nawaz Dhandala
015bd0f870 refactor: Implement retry mechanism for Docker image builds in multiple workflows 2025-08-26 13:12:18 +01:00
Nawaz Dhandala
383c145186 refactor: Integrate retry mechanism for Docker image builds in workflows 2025-08-26 13:06:55 +01:00
Simon Larsen
f155795e6b fix: Remove single quotes from changelog delimiter for correct output formatting 2025-08-26 11:56:22 +01:00
Nawaz Dhandala
757f5b5721 refactor: Improve type annotations for better clarity in error handling 2025-08-26 11:42:15 +01:00
Nawaz Dhandala
694215df06 refactor: Improve code formatting for better readability in multiple files 2025-08-26 11:40:01 +01:00
Nawaz Dhandala
0eb6022f1d Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-08-26 11:38:10 +01:00
Nawaz Dhandala
3109006828 refactor: Replace regex literals with RegExp constructor for improved clarity in MarkdownViewer and StringUtils 2025-08-26 11:38:08 +01:00
Simon Larsen
272695bd11 feat: Enhance error handling and logging in processMetricsAsync and processTracesAsync methods for improved robustness 2025-08-26 11:36:47 +01:00
Simon Larsen
330e3bc106 fix: Correct syntax error in JavaScript expression example for incoming request monitors 2025-08-26 11:26:01 +01:00
Nawaz Dhandala
c7876bf3a3 refactor: Improve regex pattern for fact extraction and enhance code formatting in OtelIngestService 2025-08-26 11:22:36 +01:00
Simon Larsen
345ada5404 feat: Enhance error handling and logging in processLogsAsync method for improved telemetry data ingestion 2025-08-26 11:16:32 +01:00
Simon Larsen
4f97b1b460 feat: Enhance image loading and layout stability across blog views 2025-08-25 10:46:19 +01:00
Nawaz Dhandala
e35ef1809f refactor: Improve code formatting and consistency across Microsoft Teams integration files 2025-08-21 14:45:34 +01:00
Simon Larsen
c2926f3542 feat: Implement structured MessageCard creation from markdown for Microsoft Teams
- Added a method to build a structured MessageCard from markdown input, enhancing message formatting for Teams.
- Extracted title, facts, and actions from markdown to improve rendering in Teams notifications.
2025-08-21 14:43:13 +01:00
Simon Larsen
9495b4bd47 feat: Add Microsoft Teams incoming webhook option to subscriber settings
- Introduced a new property for Microsoft Teams incoming webhook URL in the StatusPageSubscriberService.
- Enhanced subscriber configuration to support Microsoft Teams notifications.
2025-08-21 14:25:49 +01:00
Simon Larsen
ad3f36fdf5 refactor: Simplify Slack and Microsoft Teams notification handling in StatusPageSubscriberService
- Removed try-catch blocks for sending notifications and replaced them with promise chaining for better readability.
- Added logging for successful notification sends and error handling directly in the promise catch.
2025-08-21 14:11:06 +01:00
Simon Larsen
f2221b0a40 feat: Implement Microsoft Teams webhook validation and notification in StatusPage subscriber service
- Added validation for Microsoft Teams incoming webhook URL during subscriber setup.
- Implemented notification sending to Microsoft Teams channel upon successful subscription.
- Updated SideMenu components to reflect the new naming convention for Microsoft Teams subscribers.
2025-08-21 14:04:20 +01:00
Simon Larsen
62fbc1f4be feat: Enhance Microsoft Teams subscriber validation and handling in StatusPage API
- Added validation to ensure Microsoft Teams subscribers are only processed if enabled.
- Updated error messages to include Microsoft Teams workspace name requirements.
- Implemented handling for Microsoft Teams incoming webhook URL and workspace name in subscriber setup.
2025-08-21 13:52:35 +01:00
Simon Larsen
054a2bc8f5 feat: Enable Microsoft Teams subscribers in StatusPage API 2025-08-21 13:49:28 +01:00
Simon Larsen
896787109c feat: Add Microsoft Teams subscriber option to Email, Slack, and SMS subscription pages 2025-08-21 13:47:13 +01:00
Simon Larsen
3a55fcc872 feat: Update microsoftTeamsIncomingWebhookUrl column type to text and add migration 2025-08-21 13:27:44 +01:00
Simon Larsen
2945a48d05 feat: Update microsoftTeamsWorkspaceName column type to VeryLongText and add migration 2025-08-21 13:15:44 +01:00
Simon Larsen
da3a7ddb2e feat: Add migration for Microsoft Teams subscriber functionality in StatusPage 2025-08-21 12:57:16 +01:00
Simon Larsen
04a0bfedaa fix: Make Microsoft Teams subscriber prop required in SideMenu component 2025-08-21 12:17:00 +01:00
Simon Larsen
fa5c7b1e73 feat: Add Microsoft Teams subscriber functionality
- Implemented Microsoft Teams subscribers in the dashboard side menu.
- Created Microsoft Teams subscriber settings page with toggle options.
- Added routes for Microsoft Teams subscribers in the routing configuration.
- Updated page map and route map to include Microsoft Teams subscriber paths.
- Enhanced the app state management to handle Microsoft Teams subscription settings.
- Integrated Microsoft Teams notification sending in the announcement and incident jobs.
- Developed Microsoft Teams subscription management and creation forms.
- Added UI components for managing Microsoft Teams subscribers in the status page.
2025-08-21 12:09:53 +01:00
Simon Larsen
a1c2918cd7 feat: Update homepage heading for improved clarity and emphasis on monitoring capabilities 2025-08-21 10:24:49 +01:00
Simon Larsen
91b11b12c1 fix: Update canonical links for blog posts and remove redundant canonical tags in head partials 2025-08-21 10:15:52 +01:00
Simon Larsen
778a34d631 feat: Implement fallback to commit messages in changelog if empty 2025-08-20 09:17:53 +01:00
Simon Larsen
6dbd838ca4 refactor: Remove mobile redirect script from homepage for cleaner code 2025-08-19 22:23:20 +01:00
Simon Larsen
e09634dc6f feat: Enhance blog listing with featured post display and improved layout 2025-08-19 22:21:12 +01:00
Simon Larsen
af60715de2 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-19 22:11:14 +01:00
Simon Larsen
3b4c54876e feat: Update default page size for blog pagination from 50 to 24 for improved performance 2025-08-19 22:11:12 +01:00
Nawaz Dhandala
e357100e46 refactor: Remove redundant dynamic section checks from sitemap tests 2025-08-19 20:43:08 +01:00
Simon Larsen
7f3a50076d feat: Add reference section check to sitemap tests for improved coverage 2025-08-19 14:25:37 +01:00
Simon Larsen
9d182b6d55 feat: Add additional static paths to sitemap generation for improved coverage 2025-08-19 14:25:16 +01:00
Simon Larsen
33fce0b53c feat: Implement caching for home URL retrieval to improve performance 2025-08-19 14:15:47 +01:00
Nawaz Dhandala
3db8419349 refactor: Simplify error handling in BlogPostUtil by removing unused error variables 2025-08-19 13:50:35 +01:00
Nawaz Dhandala
dfc324b099 refactor: Improve code formatting and readability in Markdown and BlogPost utilities 2025-08-19 12:58:17 +01:00
Simon Larsen
36521ef37c feat: Update blog post listing to improve layout and add Open Source Commitment section 2025-08-19 12:55:09 +01:00
Simon Larsen
a6f336340e feat: Implement pagination and tag filtering for blog posts 2025-08-19 12:40:51 +01:00
Simon Larsen
c36f782192 feat: Refactor blog post listing and tags display for improved layout and user experience 2025-08-19 12:34:23 +01:00
Simon Larsen
5219f1cfc0 feat: Remove unused imports and the getNameOfGitHubUser function from BlogPostUtil class 2025-08-19 12:29:27 +01:00
Simon Larsen
7f84d50baa feat: Add optional bio field for authors and update blog post template to display it 2025-08-19 12:28:12 +01:00
Simon Larsen
cd2ce3f1a8 feat: Add a newline for improved readability in BlogPostUtil class 2025-08-19 12:15:23 +01:00
Simon Larsen
01b0e01ca8 feat: Implement caching for blog metadata and improve author resolution without GitHub API calls 2025-08-19 12:07:33 +01:00
Simon Larsen
73dc6bb5db feat: Remove social media image display from blog post template 2025-08-19 11:55:38 +01:00
Simon Larsen
ab7fc1c244 feat: Enhance Markdown renderer with improved code block styling and add support for horizontal rules, emphasis, and strikethrough 2025-08-19 11:50:48 +01:00
Simon Larsen
3927bea29c feat: Enhance Markdown rendering with improved list, table, and inline code support; update tag display styling for better visual consistency 2025-08-19 11:47:21 +01:00
Simon Larsen
6060d66c2b feat: Revamp blog post layout with enhanced styling, author details, and reading time estimation 2025-08-19 11:37:10 +01:00
Nawaz Dhandala
9f4869b05f test: Enhance sitemap tests to validate presence of dynamic sections 2025-08-19 10:07:11 +01:00
Nawaz Dhandala
17bdfee012 refactor: Simplify regex usage in sitemap tests and improve middleware formatting 2025-08-19 10:05:59 +01:00
Simon Larsen
4988b9fc7a feat: Refactor mobile menu implementation for improved accessibility and usability 2025-08-19 10:04:20 +01:00
Simon Larsen
9edc6b9f18 feat: Enhance mobile navigation and improve header styling for better accessibility 2025-08-19 09:58:03 +01:00
Simon Larsen
525e19faa6 feat: Improve tab accessibility and keyboard navigation with semantic identifiers 2025-08-19 09:49:23 +01:00
Simon Larsen
588e8976d2 feat: Add middleware to inject home URL for canonical links and update canonical tag in head-basic.ejs 2025-08-19 09:47:59 +01:00
Simon Larsen
d5e28e98fb Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-19 09:39:45 +01:00
Simon Larsen
0e84bc9c40 feat: Enhance accessibility and keyboard navigation for product tabs 2025-08-19 09:39:42 +01:00
Nawaz Dhandala
39e8b1da6b refactor: Enhance type annotations and improve code readability in sitemap tests 2025-08-18 13:47:35 +01:00
Nawaz Dhandala
66c4badd94 refactor: Improve formatting of product pages check in sitemap tests 2025-08-18 13:41:01 +01:00
Simon Larsen
a245fabc34 feat: Add end-to-end tests for sitemap loading and validation 2025-08-18 13:39:19 +01:00
Nawaz Dhandala
fa9fce2774 refactor: Improve type annotations and error handling in various modules 2025-08-18 12:59:17 +01:00
Nawaz Dhandala
a256f4be54 Refactor logging statements for improved readability and consistency across services
- Updated logging statements in Sitemap.ts to enhance code clarity.
- Reformatted logger.info calls in IncomingRequestIngest, OpenTelemetryIngest, Probe, ProbeIngest, and ServerMonitorIngest to use multi-line formatting for better readability.
- Adjusted import statements in Probe to follow a consistent multi-line format.
2025-08-18 12:48:23 +01:00
Simon Larsen
4869172648 feat: Ensure home URL is prioritized in sitemap XML generation 2025-08-18 12:46:45 +01:00
Simon Larsen
1abd323b00 feat: Refactor sitemap generation and clean up unused imports 2025-08-18 12:45:06 +01:00
Simon Larsen
fa196a55cd feat: Update XML builder import and fix attribute assignment in URL set creation 2025-08-18 12:32:57 +01:00
Simon Larsen
29b4417aca feat: Update robots.txt to remove disallowed paths and simplify access 2025-08-18 12:31:57 +01:00
Simon Larsen
29c0d7e7e9 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-16 15:04:23 +01:00
Simon Larsen
bfbe2437c0 feat: Add concurrency logging for various ingest services 2025-08-16 15:04:10 +01:00
Nawaz Dhandala
ca0e082daf refactor: Simplify mock setup for ProjectUserService in TeamMemberService tests 2025-08-15 19:06:41 +01:00
Nawaz Dhandala
1987b1c42e refactor: Add type annotations for domain and verificationText variables in DNS tests 2025-08-15 16:31:23 +01:00
Nawaz Dhandala
38be6edec3 feat: Improve DNS error handling with user-friendly messages and enhance tests for TXT and CNAME record verification 2025-08-15 16:29:41 +01:00
Simon Larsen
b80dda6d1a feat: Enhance DNS error handling with user-friendly messages and add tests for TXT and CNAME record verification 2025-08-15 16:23:56 +01:00
Simon Larsen
f65b2711ca feat: Change Repeat Policy Times column type from Boolean to Number 2025-08-15 11:49:57 +01:00
Simon Larsen
151c3d8c52 feat: Update logging scripts in package.json to include follow-logs command and adjust logs command 2025-08-15 11:48:16 +01:00
Simon Larsen
f17ae36dce docs: Update TerraformBuild.md to clarify restrictions on editing API key and oneuptime_url variables 2025-08-15 11:45:31 +01:00
Simon Larsen
777c6948ad feat: Add Terraform provider generation and installation instructions 2025-08-15 11:42:03 +01:00
Simon Larsen
1c6f9adbcb Merge branch 'release' of github.com:OneUptime/oneuptime into release 2025-08-14 13:52:14 +01:00
Simon Larsen
6d1b3f8568 Merge branch 'master' into release 2025-08-14 13:52:00 +01:00
Simon Larsen
11526816d1 feat: Add onCallScheduleId to UserNotificationRuleService and UserOnCallLogService for enhanced tracking 2025-08-14 13:44:45 +01:00
Nawaz Dhandala
bf190b6a32 refactor: Clean up code formatting and improve readability across multiple services and components 2025-08-14 13:10:43 +01:00
Simon Larsen
4736ea8227 feat: Refine extractSayMessagesFromCallRequest to focus on main messages for call summary 2025-08-14 12:59:38 +01:00
Simon Larsen
2cb4281fc3 feat: Update viewPageRoute in ExecutionLogsTable to use RouteUtil for dynamic route population 2025-08-14 12:47:16 +01:00
Simon Larsen
505ed980c3 feat: Improve sayMessage extraction from onInputCallRequest in CallService 2025-08-14 12:44:47 +01:00
Simon Larsen
a0b77c94b0 feat: Enhance message extraction in CallService to include onInputCallRequest messages 2025-08-14 12:37:46 +01:00
Simon Larsen
bb996ddaa2 feat: Add OnCall-related fields to notification services for enhanced tracking 2025-08-14 12:26:51 +01:00
Simon Larsen
a2f8e49bc1 feat: Enhance channel retrieval in Slack and MicrosoftTeams with error handling and fallback mechanism 2025-08-14 11:38:37 +01:00
Simon Larsen
4d6086b7fd feat: Enhance modal display in PushLogsTable with Markdown support for better formatting 2025-08-14 11:26:20 +01:00
Simon Larsen
f84a1db36a refactor: Improve modal text handling in CallLogsTable and remove unused Device Type column in PushLogsTable 2025-08-14 11:21:20 +01:00
Simon Larsen
3aa4214e54 fix: Update condition for rendering placeholder in Detail component for better null handling 2025-08-14 11:12:53 +01:00
Simon Larsen
2fb8341f9c feat: Add default value for actionType in WorkspaceNotificationLog for improved tracking 2025-08-13 21:10:09 +01:00
Simon Larsen
888d18d0a3 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-13 21:01:53 +01:00
Simon Larsen
7f8270fac1 refactor: Add actionType to log in send message functionality for better tracking 2025-08-13 21:01:46 +01:00
Simon Larsen
318c1516cd Merge pull request #1981 from OneUptime/master
Release
2025-08-13 19:50:22 +01:00
Nawaz Dhandala
0343dcca93 refactor: Improve mail sending logic in UserService for better readability and consistency 2025-08-13 19:50:05 +01:00
Simon Larsen
7728e38029 refactor: Rename messageSummary to message in WorkspaceNotificationLog and related services for consistency 2025-08-13 19:49:36 +01:00
Simon Larsen
83a0efcbb9 refactor: Remove length restriction on joined strings in WorkspaceNotificationRuleService for improved readability 2025-08-13 19:42:17 +01:00
Simon Larsen
577ba9436e refactor: Simplify return logic in Service class and remove unnecessary TypeScript ignore comment in StatusPagesRoutes 2025-08-13 19:41:37 +01:00
Simon Larsen
a521f42417 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-13 19:38:06 +01:00
Simon Larsen
1002616ab3 refactor: Remove redundant userId parameter from service calls for cleaner code 2025-08-13 19:38:02 +01:00
Nawaz Dhandala
13adbd2443 refactor: Update MigrationName1755109893911 for consistent formatting and include in index 2025-08-13 19:36:34 +01:00
Simon Larsen
12b82252f1 refactor: Remove unnecessary await from CallService.makeCall in UserNotificationRuleService and UserNotificationSettingService for improved performance 2025-08-13 19:35:43 +01:00
Simon Larsen
bdb9cb9b9a Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-13 19:32:27 +01:00
Simon Larsen
c5e19db669 refactor: Add deviceName column to PushNotificationLog and update default actionType in WorkspaceNotificationLog for improved tracking 2025-08-13 19:32:23 +01:00
Nawaz Dhandala
345bdf80e1 refactor: Update device handling in PushNotification to support new devices format and improve error handling 2025-08-13 19:29:55 +01:00
Nawaz Dhandala
c4bf5e5001 refactor: Enhance device handling in PushNotification and improve type safety in PushNotificationService and PushLogsTable 2025-08-13 19:25:27 +01:00
Nawaz Dhandala
a3685b3698 refactor: Update push notification handling to use devices array with optional device names for improved clarity 2025-08-13 19:20:27 +01:00
Nawaz Dhandala
388f6e3530 refactor: Add deviceName field to PushNotificationLog and update PushLogsTable for improved device tracking 2025-08-13 19:09:32 +01:00
Nawaz Dhandala
0493dabb93 refactor: Remove unnecessary whitespace in makeCall method for improved code consistency 2025-08-13 18:57:10 +01:00
Simon Larsen
2383b2d352 refactor: Replace userBelongsToTeamId with teamId in CallService, UserNotificationRuleService, and UserNotificationSettingService for consistency 2025-08-13 18:56:21 +01:00
Simon Larsen
c526c0e320 refactor: Replace userBelongsToTeamId and overridedByUserId with teamId in notification services for consistency 2025-08-13 18:45:42 +01:00
Nawaz Dhandala
7d607608b3 refactor: Enhance user display handling in notification log tables for improved clarity 2025-08-13 18:18:27 +01:00
Nawaz Dhandala
abece559ea refactor: Simplify onClick handlers in CallLogsTable and EmailLogsTable for improved readability 2025-08-13 18:09:46 +01:00
Simon Larsen
f9b0c499ed refactor: Simplify props in CallLogsTable, EmailLogsTable, PushLogsTable, SmsLogsTable, and WorkspaceLogsTable for improved readability and maintainability 2025-08-13 18:07:26 +01:00
Nawaz Dhandala
38594f5198 refactor: Align query prop indentation in PushLogsTable, SmsLogsTable, and WorkspaceLogsTable for consistency 2025-08-13 18:00:41 +01:00
Simon Larsen
8f08ec42c7 refactor: Update query prop type to use Query<BaseModel> for improved type safety in log tables 2025-08-13 17:59:59 +01:00
Simon Larsen
8c697149e3 refactor: Remove unused log components (CallLog, EmailLog, PushLog, SmsLog) 2025-08-13 17:57:56 +01:00
Simon Larsen
2ff3dee440 refactor: Remove CallLog, EmailLog, and SmsLog components to streamline dashboard settings 2025-08-13 17:52:07 +01:00
Nawaz Dhandala
c0e8193614 refactor: Update NotificationLogsTabs to use typed Query object for improved type safety 2025-08-13 17:42:14 +01:00
Nawaz Dhandala
c1d06fdae5 refactor: Simplify component formatting in NotificationLogsTabs and related pages 2025-08-13 17:40:33 +01:00
Simon Larsen
00ed20ea68 fix: Update import path for NotificationLogs component in ScheduledMaintenanceEventsRoutes 2025-08-13 17:40:02 +01:00
Simon Larsen
db93cc8841 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-13 17:37:41 +01:00
Simon Larsen
374e8ecb4c refactor: Update NotificationLogsTabs to use query object for improved flexibility 2025-08-13 17:37:14 +01:00
Nawaz Dhandala
9ac17850a6 refactor: Simplify MailService sendMail calls and improve formatting in Notification components 2025-08-13 17:34:58 +01:00
Simon Larsen
a38d75b8f0 Refactor Notification Logs: Consolidate Tabs into NotificationLogsTabs Component
- Removed individual log components for Email, SMS, Call, Push, and Workspace from various pages.
- Replaced existing tab implementations with a unified NotificationLogsTabs component.
- Updated pages for Incidents, OnCallDuty, ScheduledMaintenanceEvents, StatusPages, and Settings to use the new NotificationLogsTabs.
- The NotificationLogsTabs component dynamically generates tabs based on the provided singular name and query key.
2025-08-13 17:32:47 +01:00
Simon Larsen
1bfdf90bca fix: Remove unnecessary userId parameter from signup request handling 2025-08-13 17:30:33 +01:00
Simon Larsen
49e3db9442 fix: Update icon in SideMenu components from List to Bell for improved clarity 2025-08-13 17:19:18 +01:00
Simon Larsen
83ab7030a4 fix: Update icon for SideMenuItem to improve visual consistency 2025-08-13 17:18:18 +01:00
Simon Larsen
76abf62917 feat: Add on-call policy related fields to notification services and API endpoints 2025-08-13 17:13:04 +01:00
Simon Larsen
a5c2f19846 fix: Remove unnecessary userId parameter from signup response handling 2025-08-13 15:59:01 +01:00
Simon Larsen
d37e783aeb fix: Remove unnecessary userId parameter from signup request handling 2025-08-13 15:58:17 +01:00
Simon Larsen
657ea0ec09 refactor: Update default messages in notification log tables to specify project context 2025-08-13 15:56:27 +01:00
Simon Larsen
e59f7a0a7f refactor: Update action type values in WorkspaceNotificationLog and related services for consistency 2025-08-13 15:55:02 +01:00
Nawaz Dhandala
35fc80de1e refactor: Rename "Initiated by" to "User" in notification log tables for consistency 2025-08-13 15:21:49 +01:00
Nawaz Dhandala
5e2dea40a3 refactor: Adjust formatting in Tabs component for improved readability 2025-08-13 15:18:30 +01:00
Nawaz Dhandala
a66f92e0b9 refactor: Simplify TabElement class assignment and clean up Tabs component structure 2025-08-13 15:16:58 +01:00
Nawaz Dhandala
a2ce7c9433 refactor: Remove unnecessary blank line before SettingsWorkspaceLog component 2025-08-13 15:02:49 +01:00
Nawaz Dhandala
eab1dc4b1b refactor: Replace SettingsWorkspaceLog component with direct import of WorkspaceLogsTable and remove unused WorkspaceLog file 2025-08-13 15:01:23 +01:00
Nawaz Dhandala
6939c70ed8 feat: Add actionType to WorkspaceNotificationLog and update OnCallDutyPolicyScheduleLayer defaults in migration 2025-08-13 14:58:11 +01:00
Simon Larsen
cce0dc8a45 feat: Add migration to include actionType in WorkspaceNotificationLog and update OnCallDutyPolicyScheduleLayer defaults 2025-08-13 14:53:05 +01:00
Simon Larsen
ec51d7b574 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-13 14:38:16 +01:00
Simon Larsen
d4129cfa8e fix: Correct permission assignment for creating incident state timelines 2025-08-13 14:38:12 +01:00
Nawaz Dhandala
1ee7c092d3 Refactor Workspace Notification Log Service and related components
- Added missing commas in migration index for consistency.
- Cleaned up whitespace in WorkspaceNotificationLogService for better readability.
- Updated logChannelCreated and logUserInvited methods to improve code clarity.
- Enhanced button press logging in Slack actions for better error handling.
- Standardized formatting in ScheduledMaintenance and Incident Slack actions.
- Improved code structure in UptimeUtil for better readability.
- Refactored Notification components in Dashboard for consistent formatting.
- Updated WorkspaceLog component to include color typing for action types.
2025-08-13 14:30:51 +01:00
Simon Larsen
daf3b13e00 refactor: Remove unused resource association logic from user invitation process 2025-08-13 14:27:09 +01:00
Simon Larsen
5035319cc6 feat: Add action type column to WorkspaceLogsTable for improved visibility 2025-08-13 14:23:17 +01:00
Simon Larsen
3d53889d1e feat: Refactor notification log components to simplify structure and improve readability 2025-08-13 14:22:19 +01:00
Simon Larsen
65b610ebbb feat: Enhance WorkspaceLog with action type display and filtering options 2025-08-13 14:09:49 +01:00
Simon Larsen
30d1b43178 feat: Add WorkspaceNotificationActionType enum for notification actions 2025-08-13 14:08:35 +01:00
Simon Larsen
d0645f5dc2 feat: Add on-call duty policy fields and constraints to log tables 2025-08-13 13:42:31 +01:00
Simon Larsen
2274c14098 feat: Add On-Call Duty Policy and Schedule Notification Logs
- Enhanced PushNotificationLog, SmsLog, and WorkspaceNotificationLog models to include relationships with OnCallDutyPolicy, OnCallDutyPolicyEscalationRule, OnCallDutyPolicySchedule, and Team.
- Introduced new NotificationLogs components for OnCallDutyPolicy and OnCallDutySchedule, allowing users to view logs for Email, SMS, Call, Push, and Workspace notifications.
- Updated SideMenu components to include links to the new Notification Logs pages for both OnCallDutyPolicy and OnCallDutySchedule.
- Added routes and page mappings for the new Notification Logs views in OnCallDutyRoutes and PageMap.
2025-08-13 13:40:32 +01:00
Simon Larsen
d1b4d3867a feat: Enhance event overlap checks for today's events in DayUptimeGraph and UptimeUtil 2025-08-13 13:18:08 +01:00
Simon Larsen
04d4712c81 feat: Add Notification Logs section and related components for scheduled maintenance events 2025-08-13 12:58:42 +01:00
Nawaz Dhandala
9c2d2b658b refactor: Simplify event overlap check for today's events in DayUptimeGraph 2025-08-13 12:37:00 +01:00
Nawaz Dhandala
fdb1444dc8 fix: Specify type for loop index in push log creation for clarity 2025-08-13 12:24:55 +01:00
Nawaz Dhandala
39f724b77f fix: Make 'name' property public in MigrationName class for consistency 2025-08-13 12:24:08 +01:00
Nawaz Dhandala
dbfa153209 feat: Add userId tracking to email notifications and enhance logging across services 2025-08-13 12:23:45 +01:00
Simon Larsen
1c8739237f feat: Add userId tracking to email notifications across various services 2025-08-13 12:13:19 +01:00
Simon Larsen
26cdaacf6b feat: Add AlertDescription lazy import and route for alert view description 2025-08-13 11:55:28 +01:00
Simon Larsen
bbc8f0c680 feat: Add userId field to various services for enhanced tracking and logging 2025-08-12 21:54:51 +01:00
Simon Larsen
61dd8e9202 feat: Add userId field to notification logs and services for tracking user actions 2025-08-12 21:33:29 +01:00
Simon Larsen
6e17832239 feat: Enhance PushNotificationService with detailed logging and error handling 2025-08-12 21:00:30 +01:00
Simon Larsen
6460827c4c refactor: Remove Thread ID column from WorkspaceLogsTable 2025-08-12 20:40:22 +01:00
Simon Larsen
7bfd810b73 feat: Integrate MarkdownViewer for modal description in WorkspaceLogsTable 2025-08-12 19:46:18 +01:00
Simon Larsen
8b17217778 refactor: Remove redundant error logging for missing threads in workspace notification service 2025-08-12 19:44:24 +01:00
Simon Larsen
19a86e9683 fix: Change type of elk variable to any in ServiceDependencyGraph component 2025-08-12 19:23:10 +01:00
Simon Larsen
d2fd46db50 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-12 17:39:52 +01:00
Simon Larsen
26cfbd07cb feat: Add server names hash tuning options to nginx configuration 2025-08-12 17:39:47 +01:00
Nawaz Dhandala
33992984e2 fix: Correct indentation for metrics endpoint exposure in WorkersFeatureSet 2025-08-12 17:38:38 +01:00
Nawaz Dhandala
e295c19b19 feat: Implement KEDA autoscaling for worker service with metrics endpoint 2025-08-12 17:37:13 +01:00
Nawaz Dhandala
51d42c8436 feat: Update no items message in Notification Logs tables to include pluralization 2025-08-12 14:57:25 +01:00
Nawaz Dhandala
50f16d0fdc Refactor Notification Logs Tables and Related Components
- Updated EmailLogsTable, PushLogsTable, and SmsLogsTable components for improved readability and consistency in code formatting.
- Enhanced the structure of props in various components to maintain uniformity.
- Refactored the return statements in several components to use consistent formatting.
- Cleaned up unnecessary whitespace and improved the organization of imports across multiple files.
- Adjusted the breadcrumb and route mapping for better clarity and maintainability.
2025-08-11 16:48:29 +01:00
Nawaz Dhandala
726ab4d7c0 Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-08-11 16:47:55 +01:00
Nawaz Dhandala
1461dd0164 feat: Add source and target positions to nodes in ServiceDependencyGraph 2025-08-11 16:47:54 +01:00
Simon Larsen
5ce1a782b3 refactor: Remove 'Subject' column from EmailLogsTable component 2025-08-11 14:41:59 +01:00
Simon Larsen
741eaec1d3 feat: Add modal functionality to Notification Logs tables for viewing details 2025-08-11 14:38:35 +01:00
Simon Larsen
2d8c931641 refactor: Standardize formatting in EmailLogsTable component 2025-08-11 14:26:05 +01:00
Simon Larsen
4db479958b refactor: Remove unused imports and simplify ServiceCatalogPage component 2025-08-11 14:26:00 +01:00
Simon Larsen
8c825f1498 refactor: Update imports in ServiceDependencyGraph and clean up AnnouncementView component 2025-08-11 14:10:48 +01:00
Simon Larsen
25426992be feat: Add route for deleting announcement view in Status Pages 2025-08-11 14:01:25 +01:00
Simon Larsen
861a72d194 feat: Enhance Notification Logs tables with singular and plural naming support 2025-08-11 13:54:54 +01:00
Simon Larsen
0857cebcfc Refactor Notification Logs: Replace ModelTable with dedicated components for Call, Email, Push, SMS, and Workspace logs
- Introduced new components: CallLogsTable, EmailLogsTable, PushLogsTable, SmsLogsTable, and WorkspaceLogsTable.
- Updated NotificationLogsSms, NotificationLogsEmail, NotificationLogsCall, NotificationLogsPush, and NotificationLogsWorkspace to utilize the new components.
- Removed redundant column and filter definitions from the individual log pages, centralizing them in the new table components.
- Enhanced code readability and maintainability by separating concerns and reducing duplication.
2025-08-11 13:28:50 +01:00
Nawaz Dhandala
975af2c22a Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-08-11 13:16:02 +01:00
Nawaz Dhandala
98d15f91b0 feat: Integrate ELK for layout management in ServiceDependencyGraph and add typings for elkjs 2025-08-11 13:15:59 +01:00
Simon Larsen
6d55b59a21 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-11 12:47:35 +01:00
Simon Larsen
8a27651d84 feat: Add Notification Logs section and related components for Status Pages 2025-08-11 12:45:05 +01:00
Nawaz Dhandala
6a35dffcb5 feat: Update ServiceDependencyGraph to enhance edge styling and add read-only view styles 2025-08-11 12:34:49 +01:00
Nawaz Dhandala
1e4c46bb3f feat: Enhance ServiceDependencyGraph with luminance-based text color and update SideMenu icon 2025-08-11 12:33:11 +01:00
Simon Larsen
fe44c0fde4 feat: Add migration for WorkspaceNotificationLog table and related constraints 2025-08-11 12:09:54 +01:00
Nawaz Dhandala
089f612ec4 refactor: Improve code formatting and consistency across various components and routes 2025-08-11 12:01:59 +01:00
Simon Larsen
8dbd9e7430 Merge pull request #1982 from OneUptime/service-catalog-dependency
feat: Implement Service Catalog Dependency Graph and associated layou…
2025-08-11 11:58:53 +01:00
Simon Larsen
66eb9eede0 feat: Update notification log routes and components for consistency across Alerts, Incidents, Settings, and Status Pages 2025-08-11 11:57:02 +01:00
Nawaz Dhandala
e8db6fcb7f feat: Implement Service Catalog Dependency Graph and associated layout components 2025-08-11 11:47:08 +01:00
Simon Larsen
d9e7f44590 feat: Consolidate notification logs into unified components across Alerts, Incidents, Settings, and Status Pages 2025-08-10 15:20:14 +01:00
Simon Larsen
b7df0a7d05 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-10 14:51:25 +01:00
Nawaz Dhandala
4101954862 refactor: Enhance type definitions and improve message summary functions in WorkspaceNotificationRuleService 2025-08-10 14:51:09 +01:00
Nawaz Dhandala
d68e4737e7 refactor: Improve code formatting and readability across multiple components 2025-08-10 14:46:44 +01:00
Nawaz Dhandala
bfb80388a0 Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-08-10 14:45:52 +01:00
Nawaz Dhandala
1beb96345b feat: Add Workspace Logs functionality across various pages
- Introduced Workspace Logs link in the SideMenu for Alerts, Incidents, Settings, and Status Pages.
- Created new routes for viewing Workspace Logs in Alerts, Incidents, Settings, and Status Pages.
- Added WorkspaceNotificationLog model to handle logs related to messages sent to Slack and Microsoft Teams.
- Implemented WorkspaceNotificationLogService for managing log entries.
- Developed UI components for displaying Workspace Logs in Alerts, Incidents, Settings, and Status Pages.
- Added filtering options for Workspace Logs based on status and workspace type.
2025-08-10 14:45:50 +01:00
Simon Larsen
1eb2af737d feat: Add routes for viewing alert, incident, and announcement logs 2025-08-10 14:28:00 +01:00
Simon Larsen
18f756a29b Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-10 14:21:36 +01:00
Simon Larsen
002f98720c feat: Add route for Push Logs settings page 2025-08-10 14:21:32 +01:00
Nawaz Dhandala
fdf5aacc2b Refactor notification log components for improved readability and consistency
- Updated AlertPushLogs, AlertSmsLogs, IncidentCallLogs, IncidentSmsLogs, IncidentEmailLogs, and related components to enhance code formatting and structure.
- Improved the layout of column definitions and filter options for better readability.
- Ensured consistent use of object destructuring and formatting across components.
- Added missing line breaks and indentation for clarity.
- Updated query and cardProps formatting for consistency across components.
2025-08-10 13:28:44 +01:00
Simon Larsen
574cad6806 feat: Add migration for PushNotificationLog table and related constraints 2025-08-10 13:27:28 +01:00
Simon Larsen
34c4ae947b feat: Add Push Notification Logs functionality
- Introduced PushNotificationLog model to track push notifications sent to users.
- Added permissions for reading push logs in the Permission enum.
- Updated various side menus to include links to Push Logs in Alerts, Incidents, and Settings.
- Created routes for viewing Push Logs in Alerts, Incidents, and Status Pages.
- Implemented UI components for displaying Push Logs in respective pages.
- Added filtering and column configuration for Push Logs tables.
- Integrated PushStatus enum to manage the status of push notifications.
- Implemented PushNotificationLogService for database interactions related to push logs.
2025-08-10 13:25:53 +01:00
Simon Larsen
8d9fc46506 feat: Add migration for new fields and constraints in CallLog, EmailLog, and SmsLog 2025-08-09 22:50:27 +01:00
Simon Larsen
c41fbefdcb feat: Add status page announcement logs to Call, Email, and SMS logs
- Enhanced CallLog, EmailLog, and SmsLog models to include relationships with StatusPageAnnouncement.
- Updated CallService, MailService, and SmsService to handle statusPageAnnouncementId.
- Introduced AnnouncementViewLayout and AnnouncementSideMenu for better navigation.
- Created dedicated components for viewing Email, SMS, and Call logs related to announcements.
- Added routes for viewing logs and deleting announcements.
- Implemented filtering and display of logs in the UI.
2025-08-09 22:47:24 +01:00
Simon Larsen
3e47051233 Add notification logs for alerts and incidents
- Implemented Email, SMS, and Call logs for alerts in the dashboard.
- Created corresponding components for viewing logs: AlertEmailLogs, AlertSmsLogs, AlertCallLogs.
- Added routes for accessing alert notification logs.
- Enhanced the SideMenu to include links to notification logs for alerts.
- Implemented Email, SMS, and Call logs for incidents in the dashboard.
- Created corresponding components for viewing logs: IncidentEmailLogs, IncidentSmsLogs, IncidentCallLogs.
- Added routes for accessing incident notification logs.
- Enhanced the SideMenu to include links to notification logs for incidents.
- Updated various services to include statusPageId and incidentId where necessary for better tracking.
2025-08-09 21:09:57 +01:00
Simon Larsen
8219f44708 fix: Adjust job removal counts in Queue class to manage Redis bloat more effectively 2025-08-08 22:05:54 +01:00
Simon Larsen
59e6505aa3 Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-08 22:03:46 +01:00
Simon Larsen
1f971b932a feat: Implement initial cleanup for legacy jobs in Queue class to manage memory and prevent Redis bloat 2025-08-08 22:03:43 +01:00
Nawaz Dhandala
d0e12ae86f fix: Adjust indentation for improved readability in Config and Routes files 2025-08-08 21:56:35 +01:00
Simon Larsen
cd11a450cd feat: Introduce configurable concurrency settings for ingest workers in environment variables 2025-08-08 21:52:49 +01:00
Simon Larsen
c0259fc041 feat: Add concurrency setting for OpenTelemetry Ingest worker and update related configurations 2025-08-08 21:21:53 +01:00
Simon Larsen
db1f5a29bb fix: Update notification handling to mark announcements and public notes as Skipped when no related entities are found 2025-08-08 19:17:55 +01:00
Simon Larsen
a9ecaf2dc8 fix: Update incident handling to mark subscriber notifications as Skipped when no monitors are attached 2025-08-08 19:14:52 +01:00
Nawaz Dhandala
138aad596a Refactor logging statements for improved readability and consistency across worker jobs; ensure all debug messages are formatted uniformly. Update migration index to include trailing comma for consistency. Simplify route initialization in Workers feature set. 2025-08-08 18:53:40 +01:00
Simon Larsen
2577b339aa fix: Reorder route initialization to ensure worker routes are registered before default catch-alls 2025-08-08 18:44:09 +01:00
Simon Larsen
80e7731cca fix: Remove ClusterKeyAuthorization middleware from inspector route 2025-08-08 18:13:03 +01:00
Simon Larsen
9da7b258f9 feat: Add migration to rename subscriber notification fields and update database schema 2025-08-08 17:48:07 +01:00
Simon Larsen
0ec3b1aa39 fix: Remove obsolete migration files and update index to reflect changes 2025-08-08 17:42:27 +01:00
Simon Larsen
7a9bb22813 fix: Add UpdateSubscriberNotificationStatusToEnum migration for subscriber notification status updates 2025-08-08 17:34:12 +01:00
Simon Larsen
92550ac7d6 fix: Remove unnecessary createdAt condition in subscriber notification jobs and add debug logging for better traceability 2025-08-08 16:56:47 +01:00
Nawaz Dhandala
101df5b9b7 fix: Refactor error message in StatusPageDelete for better readability and clarity 2025-08-08 15:17:54 +01:00
Simon Larsen
c3d7672935 fix: Remove unnecessary NOT NULL constraint on subscriberNotificationStatusOnIncidentCreated in Incident table migration 2025-08-08 15:08:03 +01:00
Simon Larsen
859c6378af fix: Update Dockerfile to use apt-get for installing bash and curl 2025-08-08 14:05:51 +01:00
Simon Larsen
620979eab2 fix: Correct typo in notification status message 2025-08-08 13:37:52 +01:00
Simon Larsen
0aa1c51efa fix: Update error message in StatusPageDelete to clarify environment variable setup for Docker and Helm 2025-08-08 13:37:13 +01:00
Simon Larsen
1985e9fc25 fix: Update error message in StatusPageDelete to include environment variable requirement for custom domains 2025-08-08 13:35:27 +01:00
Simon Larsen
ba4093838b fix: Add type assertion for categoryColors in ChartLegend to ensure correct type usage 2025-08-07 22:31:54 +01:00
Nawaz Dhandala
4bd7902afe fix: Refactor ResourceGenerator to improve type annotations and code clarity 2025-08-07 22:05:47 +01:00
Simon Larsen
5c300ed513 feat: Enhance update method to conditionally include fields based on change detection 2025-08-07 22:03:21 +01:00
Simon Larsen
c4a50e853c feat: Add logging for unauthorized update attempts in ColumnPermissions 2025-08-07 21:29:13 +01:00
Simon Larsen
20c1f13876 fix: Exclude computed fields from default empty list assignment in ResourceGenerator 2025-08-07 21:22:48 +01:00
Simon Larsen
09426ed6be Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-07 21:11:42 +01:00
Nawaz Dhandala
675a031ee6 fix: Correct return type of getYAxisDomain function to match expected output 2025-08-07 21:02:59 +01:00
Simon Larsen
92986ac1f8 feat: Add isDefaultValueColumn flag to Downtime Monitor Statuses field in StatusPage model 2025-08-07 17:38:07 +01:00
Simon Larsen
2b95d608dc fix: Remove redundant build command for darwin arm architecture 2025-08-07 16:55:43 +01:00
Nawaz Dhandala
2696071933 fix: Correct formatting in ProjectSSO and UserNotificationSetting models; update conditional logic in DatabaseService 2025-08-07 16:46:14 +01:00
Nawaz Dhandala
684a61b599 feat: Add default values for boolean fields in various database models 2025-08-07 16:45:33 +01:00
Nawaz Dhandala
633a89161e Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-08-07 15:03:02 +01:00
Nawaz Dhandala
fd24781783 refactor: Optimize onBarClick and shape rendering logic in BarChart component 2025-08-07 15:03:00 +01:00
Simon Larsen
903b13d515 feat: Handle null values for required fields in data processing 2025-08-07 14:48:01 +01:00
Simon Larsen
58a128a05e Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-07 14:45:51 +01:00
Simon Larsen
ec1d567813 feat: Set default values for status page configuration options 2025-08-07 14:45:48 +01:00
Nawaz Dhandala
0a53161eac refactor: Improve type annotations and code consistency across various components 2025-08-07 14:31:13 +01:00
Nawaz Dhandala
83b91af708 Refactor code for consistency and readability across various components
- Updated import statements for better formatting in multiple files.
- Added semicolons for consistency in BarChart and SparkChart components.
- Improved code readability by using braces for single-line if statements in various functions.
- Enhanced the structure of return statements for clarity in SubscriberNotificationStatus and other components.
- Refactored map functions to use explicit return statements for better readability.
- Cleaned up whitespace and formatting in multiple files for a more uniform code style.
2025-08-07 13:55:08 +01:00
Simon Larsen
3fefee8725 feat: Enhance notification status handling and improve UI components 2025-08-07 13:49:53 +01:00
Simon Larsen
9b2cc7d377 feat: Update create permissions for Incident and Scheduled Maintenance models 2025-08-07 12:52:00 +01:00
Simon Larsen
1fb71ed2e3 feat: Implement subscriber notification status handling across multiple services 2025-08-07 12:46:40 +01:00
Simon Larsen
94a5abdb31 feat: Add SparkChart component with Area, Line, and Bar chart implementations 2025-08-07 11:52:44 +01:00
Simon Larsen
73f4559943 feat: Refactor BarChart component for improved type safety and event handling 2025-08-07 11:47:59 +01:00
Simon Larsen
9c3c6ee4e9 feat: Add BarChart component for enhanced data visualization 2025-08-07 11:29:19 +01:00
Simon Larsen
56743214a0 feat: Update button style in SubscriberNotificationStatus for improved UI consistency 2025-08-07 11:29:14 +01:00
Simon Larsen
9136c6d40e feat: Update color imports in SubscriberNotificationStatus for consistent branding 2025-08-07 11:23:46 +01:00
Simon Larsen
920a9baee9 feat: Update ConfirmModal behavior in SubscriberNotificationStatus for improved user interaction 2025-08-07 11:20:23 +01:00
Simon Larsen
1c4aad2d81 feat: Add SubscriberNotificationStatus component to IncidentViewStateTimeline and ScheduledMaintenanceDelete for enhanced notification display 2025-08-07 11:17:34 +01:00
Simon Larsen
8a4644922a feat: Add textColor prop to IconText component and update SubscriberNotificationStatus to utilize it 2025-08-07 11:04:20 +01:00
Simon Larsen
c3f4b7d3d4 feat: Enhance SubscriberNotificationStatus component with IconText and ConfirmModal for improved status display and user interaction 2025-08-07 10:54:10 +01:00
Simon Larsen
6f7c0814ee feat: Implement IconText component and refactor CheckboxViewer to use it 2025-08-07 10:49:21 +01:00
Nawaz Dhandala
77cd3fc4c0 refactor: Enhance type definitions for handleResendNotification and getNotificationStatusInfo across components 2025-08-06 16:02:57 +01:00
Nawaz Dhandala
e7cbc3d739 Refactor notification status assignments and improve code readability in incident and scheduled maintenance notification jobs
- Updated subscriber notification status assignments for better readability by breaking long lines.
- Added handling for non-visible scheduled maintenance events to set status to Skipped.
- Improved error handling and logging for scheduled maintenance public notes and state timelines.
- Ensured consistent formatting and structure across notification jobs for clarity and maintainability.
2025-08-06 15:41:28 +01:00
Simon Larsen
6d14ea19b9 feat: Add subscriberNotificationStatusMessage to selectMoreFields in multiple components 2025-08-06 14:47:13 +01:00
Simon Larsen
1290d3b946 fix: Remove unnecessary className from subscriberNotificationStatusMessage in PublicNote component 2025-08-06 14:29:51 +01:00
Simon Larsen
c0c58546d0 feat: Integrate Tooltip for subscriberNotificationStatusMessage in SubscriberNotificationStatus component 2025-08-06 14:17:37 +01:00
Simon Larsen
6c5ef10606 feat: Update migration files to rename subscriberNotificationFailedReason to subscriberNotificationStatusMessage and adjust imports 2025-08-06 14:05:26 +01:00
Simon Larsen
ec4c6ff7c5 feat: Rename subscriberNotificationFailedReason to subscriberNotificationStatusMessage across models and update related components 2025-08-06 14:04:06 +01:00
Simon Larsen
616e6e43ab feat: Update access control permissions for Incident, Scheduled Maintenance, and related models 2025-08-06 13:03:55 +01:00
Simon Larsen
aa08cd904b feat: Update SCIMPage to use Route for documentation link instead of URL 2025-08-06 12:34:21 +01:00
Simon Larsen
fef1c1055c feat: Integrate SubscriberNotificationStatus component in Incident and Scheduled Maintenance views, replacing checkbox logic 2025-08-06 12:31:14 +01:00
Simon Larsen
22e33809f9 feat: Remove style prop from SubscriberNotificationStatus component usage across various views 2025-08-06 11:39:59 +01:00
Simon Larsen
eb8324a3c2 feat: Replace NotificationStatusPill with SubscriberNotificationStatus component across various views 2025-08-06 11:25:35 +01:00
Simon Larsen
fa6dedc9a1 feat: Add resend notification functionality to NotificationStatusPill and related components 2025-08-06 11:24:20 +01:00
Simon Larsen
099cd807bf feat: Remove unused notification status fields and components from Announcements, Incidents, and Scheduled Maintenance tables 2025-08-06 10:58:15 +01:00
Simon Larsen
5d0b010fc4 feat: Remove unused StatusPageSCIM from AllModelTypes 2025-08-05 21:56:55 +01:00
Simon Larsen
1fc421f92a feat: Refactor notification status handling with NotificationStatusPill component 2025-08-05 21:31:08 +01:00
Simon Larsen
14a14e2341 feat: Add .claude/settings.local.json to .gitignore 2025-08-05 21:09:10 +01:00
Simon Larsen
ab23cca264 feat: Remove unused ActionButtonSchema import from multiple components 2025-08-05 20:42:06 +01:00
Simon Larsen
678a961fb9 feat: Add migration for updating subscriber notification status to the migration index 2025-08-05 18:35:49 +01:00
Simon Larsen
c2e458f035 feat: Rename notification failure reason columns for consistency and update types to text 2025-08-05 18:35:14 +01:00
Simon Larsen
4daf17dc8c feat: Add SCIM documentation for automated user provisioning and deprovisioning 2025-08-05 18:04:59 +01:00
Simon Larsen
842aa4b88d feat: Rename notification failure reason fields to subscriberNotificationFailedReason for consistency across incident and scheduled maintenance jobs 2025-08-05 18:03:33 +01:00
Simon Larsen
fd51142693 feat: Update notification failure reason fields to subscriberNotificationFailedReason and change type to VeryLongText 2025-08-05 17:57:17 +01:00
Simon Larsen
e0ddf80aa6 feat: Add migration for updating subscriber notification status and handling failure reasons in Incident and ScheduledMaintenance tables 2025-08-05 17:53:06 +01:00
Simon Larsen
e8d55164c6 feat: Update notification handling for subscribers across various jobs
- Introduced a new enum `StatusPageSubscriberNotificationStatus` to manage notification statuses (Skipped, Pending, InProgress, Success, Failed).
- Updated `SendNotificationToSubscribers` jobs for Announcements, Incidents, Scheduled Maintenance, and Public Notes to utilize the new notification status system.
- Added logic to mark notifications as Skipped if they should not be sent, and to update the status to InProgress when notifications are being processed.
- Implemented success and failure handling for notifications, updating the respective status and logging errors as needed.
- Modified database schema to replace old boolean notification flags with the new enum-based status fields, ensuring backward compatibility with existing records.
- Added migration script to handle the transition of existing records to the new notification status system.
2025-08-05 17:49:28 +01:00
Nawaz Dhandala
5cd8795e7a refactor: Clean up code formatting and improve readability in SCIM and StatusPageSCIM files 2025-08-05 12:49:04 +01:00
Simon Larsen
aebf7a4f2e feat: Remove Groups Endpoint display and enhance user identifier information in SCIM settings 2025-08-05 12:48:10 +01:00
Simon Larsen
3ef093eee1 feat: Add password generation for private users and update SideMenu icon 2025-08-05 12:46:09 +01:00
Simon Larsen
b4c530a6a5 feat: Update SCIM links and enhance HiddenText component for copy functionality 2025-08-05 12:37:34 +01:00
Simon Larsen
166228cad5 feat: Enhance SCIM configuration handling and update UI elements 2025-08-05 12:28:48 +01:00
Simon Larsen
1eb95c71fe feat: Add StatusPageSCIM API integration to BaseAPIFeatureSet 2025-08-05 12:16:24 +01:00
Simon Larsen
56f33f256b feat: Increase concurrency limit for ingest job processing to improve throughput 2025-08-05 11:13:49 +01:00
Simon Larsen
42afd164b7 feat: Increase concurrency limit for telemetry job processing to improve performance 2025-08-05 11:11:12 +01:00
Nawaz Dhandala
0796166a55 fix: Correct syntax errors in navigation group array in Nav.ts 2025-08-05 11:07:45 +01:00
Nawaz Dhandala
170bfa8515 refactor: Improve code formatting and consistency across SCIM-related files 2025-08-05 11:03:00 +01:00
Simon Larsen
2f517d8dcc feat: Update SCIM documentation URLs to use environment configuration 2025-08-05 11:00:18 +01:00
Simon Larsen
cb5c4dce45 feat: Add SCIM API documentation for user provisioning and deprovisioning 2025-08-05 10:52:57 +01:00
Simon Larsen
d9abeda60d feat: Refactor SCIM utility functions for improved modularity and logging 2025-08-05 10:33:38 +01:00
Simon Larsen
15c4c89310 feat: Add StatusPageSCIM model and related database migration
- Implemented StatusPageSCIM model with necessary fields and access controls.
- Created migration script to set up StatusPageSCIM table in the database.
- Developed StatusPageSCIMService for handling SCIM configurations, including bearer token generation.
- Added SCIM management page in the dashboard with functionalities for creating, editing, and resetting bearer tokens.
2025-08-05 10:07:24 +01:00
Simon Larsen
8c1d5652f4 feat: Change button style type for resetting bearer token to outline 2025-08-04 22:14:31 +01:00
Nawaz Dhandala
fbf87cf8d4 refactor: Add type annotations to formatUserForSCIM and resetBearerToken functions for improved type safety 2025-08-04 22:10:06 +01:00
Nawaz Dhandala
1c12ad94dd fix: Add type annotations for improved type safety in SCIM and Metrics modules 2025-08-04 22:07:10 +01:00
Nawaz Dhandala
aa09bab7c9 Refactor SCIM migrations and models; update formatting and improve readability
- Added missing comma in AllModelTypes array in Index.ts.
- Refactored MigrationName1754304193228 to improve query formatting and readability.
- Refactored MigrationName1754315774827 for consistency in formatting.
- Updated migration index file to include new migration.
- Standardized string quotes in Queue.ts for consistency.
- Cleaned up SCIMAuthorization.ts by removing unnecessary whitespace and improving log formatting.
- Refactored StartServer.ts to standardize content-type header handling.
- Improved formatting in SCIM.tsx for better readability and consistency.
- Refactored Metrics.ts to standardize queueSize extraction and type checking.
- Enhanced Probe.ts logging for clarity and consistency.
2025-08-04 21:36:11 +01:00
Simon Larsen
f7d1975ab0 feat: Add debug logging for parsing names from SCIM users 2025-08-04 21:35:30 +01:00
Simon Larsen
99c9a591cb feat: Refactor SCIM user handling to improve name parsing and team operations 2025-08-04 21:29:16 +01:00
Simon Larsen
c956d01789 feat: Enhance user name handling in SCIM responses by parsing full names into given and family names 2025-08-04 21:22:01 +01:00
Simon Larsen
17c829869b feat: Implement user activation handling by adding users to configured teams 2025-08-04 21:18:03 +01:00
Simon Larsen
d65e91a912 feat: Enhance SCIM user update logging and handle user deactivation by removing from teams 2025-08-04 21:17:28 +01:00
Simon Larsen
39710ba9b0 feat: Enhance SCIM user update and delete logging, and improve team removal logic 2025-08-04 21:12:49 +01:00
Simon Larsen
8c70a4dfae feat: Update SCIM user handling to improve pagination and remove duplicates 2025-08-04 18:00:20 +01:00
Simon Larsen
ff99055594 feat: Refactor SCIM endpoints to enhance logging and improve user query handling 2025-08-04 17:44:23 +01:00
Simon Larsen
f01cc2fd71 feat: Enhance logging for SCIM requests and responses across various endpoints 2025-08-04 17:34:28 +01:00
Simon Larsen
49b43593b1 feat: Add middleware to handle SCIM content type before JSON parsing 2025-08-04 17:25:01 +01:00
Simon Larsen
e293ffd0eb feat: Remove isEnabled column from ProjectSCIM and update related services and migrations 2025-08-04 14:58:25 +01:00
Simon Larsen
b62a5e7722 feat: Add functionality to reset Bearer Token with confirmation modals 2025-08-04 14:47:45 +01:00
Simon Larsen
8f8ba0abb8 feat: Enhance SCIM middleware logging and update SCIM page state management 2025-08-04 13:01:09 +01:00
Simon Larsen
5525556b54 feat: Rename ProjectScima to ProjectSCIM and update imports 2025-08-04 12:28:09 +01:00
Simon Larsen
669066b70a feat: Implement ProjectSCIM model and SCIM page functionality 2025-08-04 12:27:48 +01:00
Simon Larsen
76d2abed08 fix: Update SCIM endpoint URLs to include versioning 2025-08-04 12:01:50 +01:00
Simon Larsen
a6c18b3f21 fix: Remove HTTP_PROTOCOL from SCIM endpoint URLs in SCIMPage component 2025-08-04 12:01:24 +01:00
Simon Larsen
955ea7bc31 feat: Restore ProjectSCIM service with bearer token generation logic 2025-08-04 11:58:18 +01:00
Simon Larsen
45719d4656 feat: Reintroduce ProjectSCIM service with bearer token generation logic 2025-08-04 11:58:07 +01:00
Simon Larsen
796c94a261 fix: Correct import casing for ProjectSCIM across multiple files 2025-08-04 11:46:56 +01:00
Simon Larsen
d2fe822cb7 feat: Integrate ProjectSCIM model and service into the Base API feature set 2025-08-04 11:44:02 +01:00
Simon Larsen
289a369eab feat: Add migration for ProjectSCIM and ProjectScimTeam tables with foreign key constraints 2025-08-04 11:43:44 +01:00
Simon Larsen
6f07e3e119 feat: Update SCIM API endpoints to include versioning in the URL 2025-08-04 11:19:17 +01:00
Simon Larsen
8cdc1e9faf feat: Add SCIM API endpoints and middleware for user management and configuration 2025-08-04 11:09:52 +01:00
Simon Larsen
d4609a84ef feat: Implement Project SCIM service with bearer token generation 2025-08-04 10:15:34 +01:00
Simon Larsen
eb4a91a598 feat: Add SCIM settings page and routing to the dashboard 2025-08-04 10:14:47 +01:00
Simon Larsen
5bea404d6c feat: Add SCIM API integration to Identity feature set 2025-08-04 10:13:44 +01:00
Simon Larsen
df3f8b6a74 feat: Add optional stackTrace field to job data structures for enhanced error tracking 2025-08-03 12:59:51 +01:00
Simon Larsen
0c9d2c821a feat: Add advanced horizontal pod autoscaler configuration for improved scaling behavior 2025-08-02 13:05:05 +01:00
Simon Larsen
ba49aaf0c3 fix: Skip probe offline email notifications when billing is enabled 2025-08-02 12:36:50 +01:00
Simon Larsen
6ea5ad7fe8 fix: Update nextPingAt calculation to use a 2-minute offset for improved timing accuracy 2025-08-02 11:42:01 +01:00
Simon Larsen
962866d109 fix: Improve queue size extraction and handling in metrics endpoint 2025-08-01 20:58:58 +01:00
Simon Larsen
115216561c feat: Add ports configuration for OneUptime probe service 2025-08-01 20:36:30 +01:00
Simon Larsen
f709c90cc4 fix: Update probe port handling in KEDA ScaledObjects for improved configuration 2025-08-01 20:21:41 +01:00
Simon Larsen
d7f01b0189 fix: Update default port value in probe template for better configuration handling 2025-08-01 20:19:31 +01:00
Simon Larsen
c3eaa8995c fix ports 2025-08-01 20:19:10 +01:00
Simon Larsen
53b482b9f3 refactor: Update Helm templates to use new port structure in values.yaml 2025-08-01 20:13:30 +01:00
Simon Larsen
d52670f39c refactor: Update Helm templates to use new port structure in values.yaml 2025-08-01 18:22:05 +01:00
Simon Larsen
fdc1332b9e Merge branch 'master' of github.com:OneUptime/oneuptime 2025-08-01 16:17:09 +01:00
Simon Larsen
a937416663 fix: Update autoscaler condition to prevent conflicts with KEDA configuration 2025-08-01 16:17:05 +01:00
Nawaz Dhandala
546d41da81 fix: Clean up formatting and ensure consistent return structure in metrics endpoints 2025-08-01 16:13:05 +01:00
Simon Larsen
c4c6793b29 feat: Implement KEDA autoscaling configuration for probes and add metrics endpoints 2025-08-01 15:38:04 +01:00
Simon Larsen
c894b112e6 fix: Await monitorResource call to ensure proper error handling in incoming request processing 2025-08-01 14:34:17 +01:00
Simon Larsen
304baf1bb4 fix: Await monitorResource call to ensure proper error handling in probe response processing 2025-08-01 14:33:17 +01:00
Simon Larsen
9adea6b1ba feat: Remove Helm annotations for post-install and post-upgrade hooks from templates 2025-08-01 14:01:04 +01:00
Simon Larsen
5498521e02 feat: Add Helm annotations for post-install and post-upgrade hooks 2025-08-01 13:47:52 +01:00
Simon Larsen
9e97c6ddbc feat: Update autoscaler conditions for fluent-ingest, incoming-request-ingest, probe-ingest, and server-monitor-ingest templates 2025-08-01 13:23:39 +01:00
Nawaz Dhandala
63272e09f8 refactor: Simplify function parameter formatting and improve readability in various files 2025-08-01 10:45:55 +01:00
Simon Larsen
327c28afdc feat: Implement fluent ingest worker for processing queue jobs 2025-08-01 10:34:17 +01:00
Simon Larsen
896020b93b feat: Add KEDA autoscaling configuration for various ingests
- Introduced KEDA autoscaling configuration in values.yaml for probeIngest, fluentIngest, incomingRequestIngest, and serverMonitorIngest.
- Added endpoints for queue statistics, size, and failed jobs in IncomingRequestIngest and ProbeIngest APIs.
- Implemented asynchronous processing of incoming requests and probes using job queues.
- Created Metrics API for KEDA metrics integration in IncomingRequestIngest, ProbeIngest, and ServerMonitorIngest.
- Refactored IncomingRequest and Probe APIs to utilize queue services for processing.
- Added job processing logic for incoming requests and probes in respective job files.
- Implemented queue service classes for managing job addition and retrieval of queue statistics.
2025-08-01 10:29:02 +01:00
Simon Larsen
15a68472b0 feat: comment out ClusterKeyAuthorization import for KEDA debugging 2025-07-31 21:23:41 +01:00
Simon Larsen
0210480d97 feat: remove Prometheus metrics endpoint for KEDA debugging 2025-07-31 21:22:04 +01:00
Simon Larsen
72fdc06687 feat: temporarily disable authentication middleware for KEDA debugging in metrics endpoint 2025-07-31 20:52:10 +01:00
Simon Larsen
3710b81b9a feat: add replica count support for deployments in Helm templates 2025-07-31 20:03:25 +01:00
Simon Larsen
9fcb3dc2e0 feat: update cluster key handling for KEDA compatibility in authorization middleware and Helm chart 2025-07-31 19:50:25 +01:00
Simon Larsen
43e2ccf51a feat: improve secret handling in Helm chart for upgrade scenarios 2025-07-31 19:29:07 +01:00
Nawaz Dhandala
48c3d8603a fix: format code for better readability and consistency in MonitorResource and Metrics 2025-07-31 12:57:39 +01:00
Simon Larsen
9cfc912161 feat: enhance response messages for incoming request checks with time difference 2025-07-31 12:56:06 +01:00
Simon Larsen
29e3ee57ab feat: add metrics-api endpoint for queue size retrieval in KEDA autoscaling 2025-07-31 12:44:48 +01:00
Simon Larsen
be7e849822 feat: add KEDA ScaledObjects for OpenTelemetry Ingest with configurable metrics 2025-07-31 12:34:43 +01:00
Simon Larsen
59d76b601a feat: add KEDA autoscaling support for OpenTelemetry Ingest with configurable metrics 2025-07-31 12:18:57 +01:00
Simon Larsen
b77ef336b8 feat: add replica count configuration for multiple deployments in Helm templates 2025-07-31 11:47:03 +01:00
Nawaz Dhandala
7df21fe8e5 refactor: add type annotations for pagination parameters in OTelIngest 2025-07-30 22:42:24 +01:00
Nawaz Dhandala
f39e1943c7 refactor: improve code formatting and readability in Queue and TelemetryQueueService 2025-07-30 22:40:45 +01:00
Simon Larsen
966a903646 feat: implement pagination for retrieving failed jobs from the queue 2025-07-30 22:39:58 +01:00
Simon Larsen
1d9d37c6d1 refactor: optimize queue size and stats calculations by using count methods 2025-07-30 22:37:46 +01:00
Simon Larsen
7edcc4dbce feat: add endpoint to retrieve failed jobs from the queue 2025-07-30 22:37:08 +01:00
Simon Larsen
0939294d22 Refactor code structure for improved readability and maintainability 2025-07-30 19:45:46 +01:00
Simon Larsen
dbcbfe5f79 refactor: simplify telemetry processing worker initialization and remove unused export 2025-07-30 19:25:52 +01:00
Simon Larsen
a638972817 feat: update @oneuptime/common dependency in test-release workflow 2025-07-30 16:44:05 +01:00
Simon Larsen
37c6310465 feat: update @oneuptime/common to version 7.0.4800 and adjust workflow dependencies 2025-07-30 16:42:39 +01:00
Nawaz Dhandala
a7d38389fd style: improve formatting and consistency in Prometheus metrics generation 2025-07-30 16:30:26 +01:00
Nawaz Dhandala
2f55336db7 Merge branch 'master' of https://github.com/OneUptime/oneuptime 2025-07-30 16:29:25 +01:00
Nawaz Dhandala
f99a15b95b refactor: enhance type annotations for better clarity in queue processing methods 2025-07-30 16:28:53 +01:00
Simon Larsen
de5bff2ffe feat: add Prometheus metrics endpoint for telemetry queue monitoring 2025-07-30 16:26:38 +01:00
Nawaz Dhandala
cef2764499 style: format code for better readability and consistency across multiple files 2025-07-30 16:22:26 +01:00
524 changed files with 32510 additions and 7217 deletions

View File

@@ -23,7 +23,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./Accounts/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Accounts/Dockerfile .
docker-build-isolated-vm:
runs-on: ubuntu-latest
@@ -38,7 +42,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./IsolatedVM/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./IsolatedVM/Dockerfile .
docker-build-home:
runs-on: ubuntu-latest
@@ -53,7 +61,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./Home/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Home/Dockerfile .
docker-build-worker:
runs-on: ubuntu-latest
@@ -68,7 +80,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./Worker/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Worker/Dockerfile .
docker-build-workflow:
runs-on: ubuntu-latest
@@ -83,7 +99,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./Workflow/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Workflow/Dockerfile .
docker-build-api-reference:
runs-on: ubuntu-latest
@@ -98,7 +118,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./APIReference/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./APIReference/Dockerfile .
docker-build-docs:
runs-on: ubuntu-latest
@@ -113,7 +137,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./Docs/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Docs/Dockerfile .
docker-build-otel-collector:
@@ -129,7 +157,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./OTelCollector/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./OTelCollector/Dockerfile .
docker-build-app:
runs-on: ubuntu-latest
@@ -145,7 +177,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./App/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./App/Dockerfile .
docker-build-copilot:
@@ -161,7 +197,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./Copilot/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Copilot/Dockerfile .
docker-build-e2e:
runs-on: ubuntu-latest
@@ -177,7 +217,11 @@ jobs:
# build image for accounts service
- name: build docker image
run: sudo docker build -f ./E2E/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./E2E/Dockerfile .
docker-build-admin-dashboard:
runs-on: ubuntu-latest
@@ -192,7 +236,11 @@ jobs:
# build image for home
- name: build docker image
run: sudo docker build -f ./AdminDashboard/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./AdminDashboard/Dockerfile .
docker-build-dashboard:
runs-on: ubuntu-latest
@@ -207,7 +255,11 @@ jobs:
# build image for home
- name: build docker image
run: sudo docker build -f ./Dashboard/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Dashboard/Dockerfile .
docker-build-probe:
runs-on: ubuntu-latest
@@ -222,7 +274,11 @@ jobs:
# build image probe api
- name: build docker image
run: sudo docker build -f ./Probe/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./Probe/Dockerfile .
docker-build-probe-ingest:
runs-on: ubuntu-latest
@@ -237,7 +293,11 @@ jobs:
# build image probe api
- name: build docker image
run: sudo docker build -f ./ProbeIngest/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./ProbeIngest/Dockerfile .
docker-build-server-monitor-ingest:
runs-on: ubuntu-latest
@@ -252,7 +312,11 @@ jobs:
# build image probe api
- name: build docker image
run: sudo docker build -f ./ServerMonitorIngest/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./ServerMonitorIngest/Dockerfile .
docker-build-open-telemetry-ingest:
runs-on: ubuntu-latest
@@ -267,7 +331,11 @@ jobs:
# build image probe api
- name: build docker image
run: sudo docker build -f ./OpenTelemetryIngest/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./OpenTelemetryIngest/Dockerfile .
docker-build-incoming-request-ingest:
runs-on: ubuntu-latest
@@ -282,7 +350,11 @@ jobs:
# build image probe api
- name: build docker image
run: sudo docker build -f ./IncomingRequestIngest/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./IncomingRequestIngest/Dockerfile .
docker-build-fluent-ingest:
runs-on: ubuntu-latest
@@ -297,7 +369,11 @@ jobs:
# build image probe api
- name: build docker image
run: sudo docker build -f ./FluentIngest/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./FluentIngest/Dockerfile .
docker-build-status-page:
runs-on: ubuntu-latest
@@ -312,7 +388,11 @@ jobs:
# build image for home
- name: build docker image
run: sudo docker build -f ./StatusPage/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./StatusPage/Dockerfile .
docker-build-test-server:
runs-on: ubuntu-latest
@@ -327,4 +407,8 @@ jobs:
# build image for mail service
- name: build docker image
run: sudo docker build -f ./TestServer/Dockerfile .
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: sudo docker build -f ./TestServer/Dockerfile .

View File

@@ -20,7 +20,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Accounts && npm install && npm run compile && npm run dep-check
- name: Compile Accounts
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Accounts && npm install && npm run compile && npm run dep-check
compile-isolated-vm:
runs-on: ubuntu-latest
@@ -32,7 +37,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd IsolatedVM && npm install && npm run compile && npm run dep-check
- name: Compile IsolatedVM
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd IsolatedVM && npm install && npm run compile && npm run dep-check
compile-common:
runs-on: ubuntu-latest
@@ -43,7 +53,12 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: latest
- run: cd Common && npm install && npm run compile && npm run dep-check
- name: Compile Common
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Common && npm install && npm run compile && npm run dep-check
compile-app:
runs-on: ubuntu-latest
@@ -55,7 +70,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd App && npm install && npm run compile && npm run dep-check
- name: Compile App
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd App && npm install && npm run compile && npm run dep-check
compile-home:
runs-on: ubuntu-latest
@@ -67,7 +87,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Home && npm install && npm run compile && npm run dep-check
- name: Compile Home
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Home && npm install && npm run compile && npm run dep-check
compile-worker:
runs-on: ubuntu-latest
@@ -79,7 +104,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Worker && npm install && npm run compile && npm run dep-check
- name: Compile Worker
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Worker && npm install && npm run compile && npm run dep-check
compile-workflow:
runs-on: ubuntu-latest
@@ -91,7 +121,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Workflow && npm install && npm run compile && npm run dep-check
- name: Compile Workflow
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Workflow && npm install && npm run compile && npm run dep-check
compile-api-reference:
runs-on: ubuntu-latest
@@ -103,7 +138,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd APIReference && npm install && npm run compile && npm run dep-check
- name: Compile API Reference
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd APIReference && npm install && npm run compile && npm run dep-check
compile-docs-reference:
runs-on: ubuntu-latest
@@ -115,7 +155,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Docs && npm install && npm run compile && npm run dep-check
- name: Compile Docs Reference
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Docs && npm install && npm run compile && npm run dep-check
compile-copilot:
runs-on: ubuntu-latest
@@ -127,7 +172,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Copilot && npm install && npm run compile && npm run dep-check
- name: Compile Copilot
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Copilot && npm install && npm run compile && npm run dep-check
compile-nginx:
runs-on: ubuntu-latest
@@ -140,7 +190,12 @@ jobs:
node-version: latest
- run: cd Common && npm install
- run: cd Nginx && npm install && npm run compile && npm run dep-check
- name: Compile Nginx
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Nginx && npm install && npm run compile && npm run dep-check
compile-infrastructure-agent:
runs-on: ubuntu-latest
@@ -150,7 +205,12 @@ jobs:
- uses: actions/checkout@v4
# Setup Go
- uses: actions/setup-go@v5
- run: cd InfrastructureAgent && go build .
- name: Compile Infrastructure Agent
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd InfrastructureAgent && go build .
compile-admin-dashboard:
@@ -164,7 +224,12 @@ jobs:
node-version: latest
- run: cd Common && npm install
- run: cd AdminDashboard && npm install && npm run compile && npm run dep-check
- name: Compile Admin Dashboard
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd AdminDashboard && npm install && npm run compile && npm run dep-check
compile-dashboard:
runs-on: ubuntu-latest
@@ -177,7 +242,12 @@ jobs:
node-version: latest
- run: cd Common && npm install
- run: cd Dashboard && npm install && npm run compile && npm run dep-check
- name: Compile Dashboard
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Dashboard && npm install && npm run compile && npm run dep-check
compile-e2e:
@@ -191,7 +261,12 @@ jobs:
node-version: latest
- run: sudo apt-get update
- run: cd Common && npm install
- run: cd E2E && npm install && npm run compile && npm run dep-check
- name: Compile E2E
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd E2E && npm install && npm run compile && npm run dep-check
compile-probe:
runs-on: ubuntu-latest
@@ -203,7 +278,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd Probe && npm install && npm run compile && npm run dep-check
- name: Compile Probe
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd Probe && npm install && npm run compile && npm run dep-check
compile-probe-ingest:
runs-on: ubuntu-latest
@@ -215,7 +295,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd ProbeIngest && npm install && npm run compile && npm run dep-check
- name: Compile Probe Ingest
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd ProbeIngest && npm install && npm run compile && npm run dep-check
compile-server-monitor-ingest:
runs-on: ubuntu-latest
@@ -227,7 +312,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd ServerMonitorIngest && npm install && npm run compile && npm run dep-check
- name: Compile Server Monitor Ingest
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd ServerMonitorIngest && npm install && npm run compile && npm run dep-check
compile-open-telemetry-ingest:
runs-on: ubuntu-latest
@@ -239,7 +329,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd OpenTelemetryIngest && npm install && npm run compile && npm run dep-check
- name: Compile Open Telemetry Ingest
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd OpenTelemetryIngest && npm install && npm run compile && npm run dep-check
compile-incoming-request-ingest:
@@ -252,7 +347,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd IncomingRequestIngest && npm install && npm run compile && npm run dep-check
- name: Compile Incoming Request Ingest
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd IncomingRequestIngest && npm install && npm run compile && npm run dep-check
compile-fluent-ingest:
runs-on: ubuntu-latest
@@ -264,7 +364,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd FluentIngest && npm install && npm run compile && npm run dep-check
- name: Compile Fluent Ingest
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd FluentIngest && npm install && npm run compile && npm run dep-check
compile-status-page:
@@ -278,7 +383,12 @@ jobs:
node-version: latest
- run: cd Common && npm install
- run: cd StatusPage && npm install && npm run compile && npm run dep-check
- name: Compile Status Page
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd StatusPage && npm install && npm run compile && npm run dep-check
compile-test-server:
runs-on: ubuntu-latest
@@ -290,7 +400,12 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd TestServer && npm install && npm run compile && npm run dep-check
- name: Compile Test Server
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd TestServer && npm install && npm run compile && npm run dep-check
compile-mcp:
runs-on: ubuntu-latest
@@ -302,4 +417,9 @@ jobs:
with:
node-version: latest
- run: cd Common && npm install
- run: cd MCP && npm install && npm run compile && npm run dep-check
- name: Compile MCP
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: cd MCP && npm install && npm run compile && npm run dep-check

File diff suppressed because it is too large Load Diff

View File

@@ -77,17 +77,21 @@ jobs:
ls -la "$PROVIDER_DIR" || true
- name: Test Go build
run: |
PROVIDER_DIR="./Terraform"
if [ -d "$PROVIDER_DIR" ] && [ -f "$PROVIDER_DIR/go.mod" ]; then
cd "$PROVIDER_DIR"
echo "🔨 Testing Go build..."
go mod tidy
go build -v ./...
echo "✅ Go build successful"
else
echo "⚠️ Cannot test build - missing go.mod or provider directory"
fi
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: |
PROVIDER_DIR="./Terraform"
if [ -d "$PROVIDER_DIR" ] && [ -f "$PROVIDER_DIR/go.mod" ]; then
cd "$PROVIDER_DIR"
echo "🔨 Testing Go build..."
go mod tidy
go build -v ./...
echo "✅ Go build successful"
else
echo "⚠️ Cannot test build - missing go.mod or provider directory"
fi
- name: Upload Terraform provider as artifact
uses: actions/upload-artifact@v4

File diff suppressed because it is too large Load Diff

1
.gitignore vendored
View File

@@ -127,3 +127,4 @@ MCP/build/
MCP/.env
MCP/node_modules
Dashboard/public/sw.js
.claude/settings.local.json

View File

@@ -2,6 +2,7 @@ import { IsBillingEnabled } from "Common/Server/EnvironmentConfig";
import { ViewsPath } from "../Utils/Config";
import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import Dictionary from "Common/Types/Dictionary";
// Retrieve resources documentation
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
@@ -16,7 +17,7 @@ export default class ServiceHandler {
// Extract page parameter from request
const page: string | undefined = req.params["page"];
const pageData: any = {};
const pageData: Dictionary<unknown> = {};
// Set default page title and description for the authentication page
pageTitle = "Authentication";

View File

@@ -4,6 +4,7 @@ import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import LocalCache from "Common/Server/Infrastructure/LocalCache";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import LocalFile from "Common/Server/Utils/LocalFile";
import Dictionary from "Common/Types/Dictionary";
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
@@ -12,9 +13,9 @@ export default class ServiceHandler {
_req: ExpressRequest,
res: ExpressResponse,
): Promise<void> {
const pageData: any = {};
const pageData: Dictionary<unknown> = {};
pageData.selectCode = await LocalCache.getOrSetString(
pageData["selectCode"] = await LocalCache.getOrSetString(
"data-type",
"select",
async () => {
@@ -22,7 +23,7 @@ export default class ServiceHandler {
},
);
pageData.sortCode = await LocalCache.getOrSetString(
pageData["sortCode"] = await LocalCache.getOrSetString(
"data-type",
"sort",
async () => {
@@ -30,7 +31,7 @@ export default class ServiceHandler {
},
);
pageData.equalToCode = await LocalCache.getOrSetString(
pageData["equalToCode"] = await LocalCache.getOrSetString(
"data-type",
"equal-to",
async () => {
@@ -38,7 +39,7 @@ export default class ServiceHandler {
},
);
pageData.equalToOrNullCode = await LocalCache.getOrSetString(
pageData["equalToOrNullCode"] = await LocalCache.getOrSetString(
"data-type",
"equal-to-or-null",
async () => {
@@ -48,7 +49,7 @@ export default class ServiceHandler {
},
);
pageData.greaterThanCode = await LocalCache.getOrSetString(
pageData["greaterThanCode"] = await LocalCache.getOrSetString(
"data-type",
"greater-than",
async () => {
@@ -58,7 +59,7 @@ export default class ServiceHandler {
},
);
pageData.greaterThanOrEqualCode = await LocalCache.getOrSetString(
pageData["greaterThanOrEqualCode"] = await LocalCache.getOrSetString(
"data-type",
"greater-than-or-equal",
async () => {
@@ -68,7 +69,7 @@ export default class ServiceHandler {
},
);
pageData.lessThanCode = await LocalCache.getOrSetString(
pageData["lessThanCode"] = await LocalCache.getOrSetString(
"data-type",
"less-than",
async () => {
@@ -78,7 +79,7 @@ export default class ServiceHandler {
},
);
pageData.lessThanOrEqualCode = await LocalCache.getOrSetString(
pageData["lessThanOrEqualCode"] = await LocalCache.getOrSetString(
"data-type",
"less-than-or-equal",
async () => {
@@ -88,7 +89,7 @@ export default class ServiceHandler {
},
);
pageData.includesCode = await LocalCache.getOrSetString(
pageData["includesCode"] = await LocalCache.getOrSetString(
"data-type",
"includes",
async () => {
@@ -98,7 +99,7 @@ export default class ServiceHandler {
},
);
pageData.lessThanOrNullCode = await LocalCache.getOrSetString(
pageData["lessThanOrNullCode"] = await LocalCache.getOrSetString(
"data-type",
"less-than-or-equal",
async () => {
@@ -108,7 +109,7 @@ export default class ServiceHandler {
},
);
pageData.greaterThanOrNullCode = await LocalCache.getOrSetString(
pageData["greaterThanOrNullCode"] = await LocalCache.getOrSetString(
"data-type",
"less-than-or-equal",
async () => {
@@ -118,7 +119,7 @@ export default class ServiceHandler {
},
);
pageData.isNullCode = await LocalCache.getOrSetString(
pageData["isNullCode"] = await LocalCache.getOrSetString(
"data-type",
"is-null",
async () => {
@@ -126,7 +127,7 @@ export default class ServiceHandler {
},
);
pageData.notNullCode = await LocalCache.getOrSetString(
pageData["notNullCode"] = await LocalCache.getOrSetString(
"data-type",
"not-null",
async () => {
@@ -134,7 +135,7 @@ export default class ServiceHandler {
},
);
pageData.notEqualToCode = await LocalCache.getOrSetString(
pageData["notEqualToCode"] = await LocalCache.getOrSetString(
"data-type",
"not-equals",
async () => {

View File

@@ -2,6 +2,7 @@ import { IsBillingEnabled } from "Common/Server/EnvironmentConfig";
import { ViewsPath } from "../Utils/Config";
import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import Dictionary from "Common/Types/Dictionary";
// Fetch a list of resources used in the application
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
@@ -17,7 +18,7 @@ export default class ServiceHandler {
// Get the 'page' parameter from the request
const page: string | undefined = req.params["page"];
const pageData: any = {};
const pageData: Dictionary<unknown> = {};
// Set the default page title and description
pageTitle = "Errors";

View File

@@ -2,6 +2,7 @@ import { IsBillingEnabled } from "Common/Server/EnvironmentConfig";
import { ViewsPath } from "../Utils/Config";
import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import Dictionary from "Common/Types/Dictionary";
// Get all resources and featured resources from ResourceUtil
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
@@ -20,10 +21,10 @@ export default class ServiceHandler {
// Get the requested page from the URL parameters
const page: string | undefined = req.params["page"];
const pageData: any = {};
const pageData: Dictionary<unknown> = {};
// Set featured resources for the page
pageData.featuredResources = FeaturedResources;
pageData["featuredResources"] = FeaturedResources;
// Set page title and description
pageTitle = "Introduction";

View File

@@ -3,7 +3,10 @@ import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import PageNotFoundServiceHandler from "./PageNotFound";
import { AppApiRoute } from "Common/ServiceRoute";
import { ColumnAccessControl } from "Common/Types/BaseDatabase/AccessControl";
import { getTableColumns } from "Common/Types/Database/TableColumn";
import {
getTableColumns,
TableColumnMetadata,
} from "Common/Types/Database/TableColumn";
import Dictionary from "Common/Types/Dictionary";
import ObjectID from "Common/Types/ObjectID";
import Permission, {
@@ -33,7 +36,7 @@ export default class ServiceHandler {
let pageTitle: string = "";
let pageDescription: string = "";
let page: string | undefined = req.params["page"];
const pageData: any = {};
const pageData: Dictionary<unknown> = {};
// Check if page is provided
if (!page) {
@@ -56,7 +59,9 @@ export default class ServiceHandler {
page = "model";
// Get table columns for current resource
const tableColumns: any = getTableColumns(currentResource.model);
const tableColumns: Dictionary<TableColumnMetadata> = getTableColumns(
currentResource.model,
);
// Filter out columns with no access
for (const key in tableColumns) {
@@ -77,12 +82,14 @@ export default class ServiceHandler {
continue;
}
if (tableColumns[key].hideColumnInDocumentation) {
if (tableColumns[key] && tableColumns[key]!.hideColumnInDocumentation) {
delete tableColumns[key];
continue;
}
tableColumns[key].permissions = accessControl;
if (tableColumns[key]) {
(tableColumns[key] as any).permissions = accessControl;
}
}
// Remove unnecessary columns
@@ -92,11 +99,11 @@ export default class ServiceHandler {
delete tableColumns["version"];
// Set page data
pageData.title = currentResource.model.singularName;
pageData.description = currentResource.model.tableDescription;
pageData.columns = tableColumns;
pageData["title"] = currentResource.model.singularName;
pageData["description"] = currentResource.model.tableDescription;
pageData["columns"] = tableColumns;
pageData.tablePermissions = {
pageData["tablePermissions"] = {
read: currentResource.model.readRecordPermissions.map(
(permission: Permission) => {
return PermissionDictionary[permission];
@@ -120,7 +127,7 @@ export default class ServiceHandler {
};
// Cache the list request data
pageData.listRequest = await LocalCache.getOrSetString(
pageData["listRequest"] = await LocalCache.getOrSetString(
"model",
"list-request",
async () => {
@@ -130,7 +137,7 @@ export default class ServiceHandler {
);
// Cache the item request data
pageData.itemRequest = await LocalCache.getOrSetString(
pageData["itemRequest"] = await LocalCache.getOrSetString(
"model",
"item-request",
async () => {
@@ -140,7 +147,7 @@ export default class ServiceHandler {
);
// Cache the item response data
pageData.itemResponse = await LocalCache.getOrSetString(
pageData["itemResponse"] = await LocalCache.getOrSetString(
"model",
"item-response",
async () => {
@@ -152,7 +159,7 @@ export default class ServiceHandler {
);
// Cache the count request data
pageData.countRequest = await LocalCache.getOrSetString(
pageData["countRequest"] = await LocalCache.getOrSetString(
"model",
"count-request",
async () => {
@@ -164,7 +171,7 @@ export default class ServiceHandler {
);
// Cache the count response data
pageData.countResponse = await LocalCache.getOrSetString(
pageData["countResponse"] = await LocalCache.getOrSetString(
"model",
"count-response",
async () => {
@@ -175,7 +182,7 @@ export default class ServiceHandler {
},
);
pageData.updateRequest = await LocalCache.getOrSetString(
pageData["updateRequest"] = await LocalCache.getOrSetString(
"model",
"update-request",
async () => {
@@ -186,7 +193,7 @@ export default class ServiceHandler {
},
);
pageData.updateResponse = await LocalCache.getOrSetString(
pageData["updateResponse"] = await LocalCache.getOrSetString(
"model",
"update-response",
async () => {
@@ -197,7 +204,7 @@ export default class ServiceHandler {
},
);
pageData.createRequest = await LocalCache.getOrSetString(
pageData["createRequest"] = await LocalCache.getOrSetString(
"model",
"create-request",
async () => {
@@ -208,7 +215,7 @@ export default class ServiceHandler {
},
);
pageData.createResponse = await LocalCache.getOrSetString(
pageData["createResponse"] = await LocalCache.getOrSetString(
"model",
"create-response",
async () => {
@@ -219,7 +226,7 @@ export default class ServiceHandler {
},
);
pageData.deleteRequest = await LocalCache.getOrSetString(
pageData["deleteRequest"] = await LocalCache.getOrSetString(
"model",
"delete-request",
async () => {
@@ -230,7 +237,7 @@ export default class ServiceHandler {
},
);
pageData.deleteResponse = await LocalCache.getOrSetString(
pageData["deleteResponse"] = await LocalCache.getOrSetString(
"model",
"delete-response",
async () => {
@@ -242,7 +249,7 @@ export default class ServiceHandler {
);
// Get list response from cache or set it if it's not available
pageData.listResponse = await LocalCache.getOrSetString(
pageData["listResponse"] = await LocalCache.getOrSetString(
"model",
"list-response",
async () => {
@@ -254,14 +261,15 @@ export default class ServiceHandler {
);
// Generate a unique ID for the example object
pageData.exampleObjectID = ObjectID.generate();
pageData["exampleObjectID"] = ObjectID.generate();
// Construct the API path for the current resource
pageData.apiPath =
pageData["apiPath"] =
AppApiRoute.toString() + currentResource.model.crudApiPath?.toString();
// Check if the current resource is a master admin API
pageData.isMasterAdminApiDocs = currentResource.model.isMasterAdminApiDocs;
pageData["isMasterAdminApiDocs"] =
currentResource.model.isMasterAdminApiDocs;
// Render the index page with the required data
return res.render(`${ViewsPath}/pages/index`, {

View File

@@ -7,6 +7,7 @@ import { ViewsPath } from "../Utils/Config";
import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import URL from "Common/Types/API/URL";
import Dictionary from "Common/Types/Dictionary";
// Fetch a list of resources used in the application
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
@@ -22,7 +23,7 @@ export default class ServiceHandler {
// Get the 'page' parameter from the request
const page: string | undefined = req.params["page"];
const pageData: any = {
const pageData: Dictionary<unknown> = {
hostUrl: new URL(HttpProtocol, Host).toString(),
};

View File

@@ -4,6 +4,7 @@ import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import LocalCache from "Common/Server/Infrastructure/LocalCache";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import LocalFile from "Common/Server/Utils/LocalFile";
import Dictionary from "Common/Types/Dictionary";
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources(); // Get all resources from ResourceUtil
@@ -15,14 +16,14 @@ export default class ServiceHandler {
let pageTitle: string = ""; // Initialize page title
let pageDescription: string = ""; // Initialize page description
const page: string | undefined = req.params["page"]; // Get the page parameter from the request
const pageData: any = {}; // Initialize page data object
const pageData: Dictionary<unknown> = {}; // Initialize page data object
// Set page title and description
pageTitle = "Pagination";
pageDescription = "Learn how to paginate requests with OneUptime API";
// Get response and request code from LocalCache or LocalFile
pageData.responseCode = await LocalCache.getOrSetString(
pageData["responseCode"] = await LocalCache.getOrSetString(
"pagination",
"response",
async () => {
@@ -33,7 +34,7 @@ export default class ServiceHandler {
},
);
pageData.requestCode = await LocalCache.getOrSetString(
pageData["requestCode"] = await LocalCache.getOrSetString(
"pagination",
"request",
async () => {

View File

@@ -3,6 +3,7 @@ import ResourceUtil, { ModelDocumentation } from "../Utils/Resources";
import { PermissionHelper, PermissionProps } from "Common/Types/Permission";
import { ExpressRequest, ExpressResponse } from "Common/Server/Utils/Express";
import { IsBillingEnabled } from "Common/Server/EnvironmentConfig";
import Dictionary from "Common/Types/Dictionary";
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
@@ -17,14 +18,14 @@ export default class ServiceHandler {
// Get the requested page
const page: string | undefined = req.params["page"];
const pageData: any = {};
const pageData: Dictionary<unknown> = {};
// Set page title and description
pageTitle = "Permissions";
pageDescription = "Learn how permissions work with OneUptime";
// Filter permissions to only include those assignable to tenants
pageData.permissions = PermissionHelper.getAllPermissionProps().filter(
pageData["permissions"] = PermissionHelper.getAllPermissionProps().filter(
(i: PermissionProps) => {
return i.isAssignableToTenant;
},

View File

@@ -4,5 +4,7 @@
"ignore": [
"greenlock.d/*"
],
"exec": "node --inspect=0.0.0.0:9229 --require ts-node/register Index.ts"
"watchOptions": {"useFsEvents": false, "interval": 500},
"env": {"TS_NODE_TRANSPILE_ONLY": "1", "TS_NODE_FILES": "false"},
"exec": "node --inspect=0.0.0.0:9229 -r ts-node/register/transpile-only Index.ts"
}

View File

@@ -66,6 +66,7 @@
"crypto-js": "^4.2.0",
"dotenv": "^16.4.4",
"ejs": "^3.1.10",
"elkjs": "^0.10.0",
"esbuild": "^0.25.5",
"express": "^4.21.1",
"formik": "^2.4.6",

View File

@@ -135,7 +135,6 @@
<link rel="apple-touch-icon-precomposed" href="/img/ou-wb.svg">
<link rel="icon" href="/img/ou-wb.svg">
<link rel="image_src" type="image/png" href="/img/hou-wb.svg">
<link rel="canonical" href="/">
<link rel="manifest" href="/manifest.json">
<meta property="og:title" content="OneUptime - One Complete Observability platform.">
<meta property="og:url" content="https://oneuptime.com">

View File

@@ -70,6 +70,7 @@
"crypto-js": "^4.2.0",
"dotenv": "^16.4.4",
"ejs": "^3.1.10",
"elkjs": "^0.10.0",
"esbuild": "^0.25.5",
"express": "^4.21.1",
"formik": "^2.4.6",

View File

@@ -69,6 +69,7 @@
"crypto-js": "^4.2.0",
"dotenv": "^16.4.4",
"ejs": "^3.1.10",
"elkjs": "^0.10.0",
"esbuild": "^0.25.5",
"express": "^4.21.1",
"formik": "^2.4.6",

View File

@@ -282,6 +282,9 @@ import ShortLinkService, {
import SmsLogService, {
Service as SmsLogServiceType,
} from "Common/Server/Services/SmsLogService";
import PushNotificationLogService, {
Service as PushNotificationLogServiceType,
} from "Common/Server/Services/PushNotificationLogService";
import SpanService, {
SpanService as SpanServiceType,
} from "Common/Server/Services/SpanService";
@@ -379,6 +382,8 @@ import Span from "Common/Models/AnalyticsModels/Span";
import ApiKey from "Common/Models/DatabaseModels/ApiKey";
import ApiKeyPermission from "Common/Models/DatabaseModels/ApiKeyPermission";
import CallLog from "Common/Models/DatabaseModels/CallLog";
import PushNotificationLog from "Common/Models/DatabaseModels/PushNotificationLog";
import WorkspaceNotificationLog from "Common/Models/DatabaseModels/WorkspaceNotificationLog";
import Domain from "Common/Models/DatabaseModels/Domain";
import EmailLog from "Common/Models/DatabaseModels/EmailLog";
import EmailVerificationToken from "Common/Models/DatabaseModels/EmailVerificationToken";
@@ -480,6 +485,9 @@ import TelemetryAttribute from "Common/Models/AnalyticsModels/TelemetryAttribute
import ExceptionInstance from "Common/Models/AnalyticsModels/ExceptionInstance";
import TelemetyException from "Common/Models/DatabaseModels/TelemetryException";
import CopilotActionTypePriority from "Common/Models/DatabaseModels/CopilotActionTypePriority";
import WorkspaceNotificationLogService, {
Service as WorkspaceNotificationLogServiceType,
} from "Common/Server/Services/WorkspaceNotificationLogService";
// scheduled maintenance template
import ScheduledMaintenanceTemplate from "Common/Models/DatabaseModels/ScheduledMaintenanceTemplate";
@@ -530,11 +538,6 @@ import WorkspaceSettingService, {
Service as WorkspaceSettingServiceType,
} from "Common/Server/Services/WorkspaceSettingService";
import ProjectUser from "Common/Models/DatabaseModels/ProjectUser";
import ProjectUserService, {
Service as ProjectUserServiceType,
} from "Common/Server/Services/ProjectUserService";
import MonitorFeed from "Common/Models/DatabaseModels/MonitorFeed";
import MonitorFeedService, {
Service as MonitorFeedServiceType,
@@ -583,6 +586,18 @@ import StatusPageAnnouncementTemplateService, {
Service as StatusPageAnnouncementTemplateServiceType,
} from "Common/Server/Services/StatusPageAnnouncementTemplateService";
// ProjectSCIM
import ProjectSCIM from "Common/Models/DatabaseModels/ProjectSCIM";
import ProjectSCIMService, {
Service as ProjectSCIMServiceType,
} from "Common/Server/Services/ProjectSCIMService";
// StatusPageSCIM
import StatusPageSCIM from "Common/Models/DatabaseModels/StatusPageSCIM";
import StatusPageSCIMService, {
Service as StatusPageSCIMServiceType,
} from "Common/Server/Services/StatusPageSCIMService";
// Open API Spec
import OpenAPI from "Common/Server/API/OpenAPI";
@@ -618,6 +633,24 @@ const BaseAPIFeatureSet: FeatureSet = {
).getRouter(),
);
// Project SCIM
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<ProjectSCIM, ProjectSCIMServiceType>(
ProjectSCIM,
ProjectSCIMService,
).getRouter(),
);
// Status Page SCIM
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<StatusPageSCIM, StatusPageSCIMServiceType>(
StatusPageSCIM,
StatusPageSCIMService,
).getRouter(),
);
// status page announcement templates
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
@@ -698,14 +731,6 @@ const BaseAPIFeatureSet: FeatureSet = {
).getRouter(),
);
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<ProjectUser, ProjectUserServiceType>(
ProjectUser,
ProjectUserService,
).getRouter(),
);
//service provider setting
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
@@ -1501,6 +1526,22 @@ const BaseAPIFeatureSet: FeatureSet = {
new BaseAPI<SmsLog, SmsLogServiceType>(SmsLog, SmsLogService).getRouter(),
);
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<PushNotificationLog, PushNotificationLogServiceType>(
PushNotificationLog,
PushNotificationLogService,
).getRouter(),
);
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<
WorkspaceNotificationLog,
WorkspaceNotificationLogServiceType
>(WorkspaceNotificationLog, WorkspaceNotificationLogService).getRouter(),
);
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<EmailLog, EmailLogServiceType>(

View File

@@ -0,0 +1,718 @@
import SCIMMiddleware from "Common/Server/Middleware/SCIMAuthorization";
import UserService from "Common/Server/Services/UserService";
import TeamMemberService from "Common/Server/Services/TeamMemberService";
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
OneUptimeRequest,
} from "Common/Server/Utils/Express";
import Response from "Common/Server/Utils/Response";
import logger from "Common/Server/Utils/Logger";
import ObjectID from "Common/Types/ObjectID";
import Email from "Common/Types/Email";
import Name from "Common/Types/Name";
import { JSONObject } from "Common/Types/JSON";
import TeamMember from "Common/Models/DatabaseModels/TeamMember";
import ProjectSCIM from "Common/Models/DatabaseModels/ProjectSCIM";
import BadRequestException from "Common/Types/Exception/BadRequestException";
import NotFoundException from "Common/Types/Exception/NotFoundException";
import OneUptimeDate from "Common/Types/Date";
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
import Query from "Common/Types/BaseDatabase/Query";
import QueryHelper from "Common/Server/Types/Database/QueryHelper";
import User from "Common/Models/DatabaseModels/User";
import {
parseNameFromSCIM,
formatUserForSCIM,
generateServiceProviderConfig,
generateUsersListResponse,
parseSCIMQueryParams,
} from "../Utils/SCIMUtils";
import { DocsClientUrl } from "Common/Server/EnvironmentConfig";
const router: ExpressRouter = Express.getRouter();
const handleUserTeamOperations: (
operation: "add" | "remove",
projectId: ObjectID,
userId: ObjectID,
scimConfig: ProjectSCIM,
) => Promise<void> = async (
operation: "add" | "remove",
projectId: ObjectID,
userId: ObjectID,
scimConfig: ProjectSCIM,
): Promise<void> => {
const teamsIds: Array<ObjectID> =
scimConfig.teams?.map((team: any) => {
return team.id;
}) || [];
if (teamsIds.length === 0) {
logger.debug(`SCIM Team operations - no teams configured for SCIM`);
return;
}
if (operation === "add") {
logger.debug(
`SCIM Team operations - adding user to ${teamsIds.length} configured teams`,
);
for (const team of scimConfig.teams || []) {
const existingMember: TeamMember | null =
await TeamMemberService.findOneBy({
query: {
projectId: projectId,
userId: userId,
teamId: team.id!,
},
select: { _id: true },
props: { isRoot: true },
});
if (!existingMember) {
logger.debug(`SCIM Team operations - adding user to team: ${team.id}`);
const teamMember: TeamMember = new TeamMember();
teamMember.projectId = projectId;
teamMember.userId = userId;
teamMember.teamId = team.id!;
teamMember.hasAcceptedInvitation = true;
teamMember.invitationAcceptedAt = OneUptimeDate.getCurrentDate();
await TeamMemberService.create({
data: teamMember,
props: {
isRoot: true,
ignoreHooks: true,
},
});
logger.debug(`SCIM Team operations - user added to team: ${team.id}`);
} else {
logger.debug(
`SCIM Team operations - user already member of team: ${team.id}`,
);
}
}
} else if (operation === "remove") {
logger.debug(
`SCIM Team operations - removing user from ${teamsIds.length} configured teams`,
);
await TeamMemberService.deleteBy({
query: {
projectId: projectId,
userId: userId,
teamId: QueryHelper.any(teamsIds),
},
skip: 0,
limit: LIMIT_PER_PROJECT,
props: { isRoot: true },
});
}
};
// SCIM Service Provider Configuration - GET /scim/v2/ServiceProviderConfig
router.get(
"/scim/v2/:projectScimId/ServiceProviderConfig",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Project SCIM ServiceProviderConfig - scimId: ${req.params["projectScimId"]!}`,
);
const serviceProviderConfig: JSONObject = generateServiceProviderConfig(
req,
req.params["projectScimId"]!,
"project",
DocsClientUrl.toString() + "/identity/scim",
);
logger.debug(
"Project SCIM ServiceProviderConfig response prepared successfully",
);
return Response.sendJsonObjectResponse(req, res, serviceProviderConfig);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Basic Users endpoint - GET /scim/v2/Users
router.get(
"/scim/v2/:projectScimId/Users",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const projectId: ObjectID = bearerData["projectId"] as ObjectID;
// Parse query parameters
const { startIndex, count } = parseSCIMQueryParams(req);
const filter: string = req.query["filter"] as string;
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}, startIndex: ${startIndex}, count: ${count}, filter: ${filter || "none"}`,
);
// Build query for team members in this project
const query: Query<TeamMember> = {
projectId: projectId,
};
// Handle SCIM filter for userName
if (filter) {
const emailMatch: RegExpMatchArray | null = filter.match(
/userName eq "([^"]+)"/i,
);
if (emailMatch) {
const email: string = emailMatch[1]!;
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}, filter by email: ${email}`,
);
if (email) {
if (Email.isValid(email)) {
const user: User | null = await UserService.findOneBy({
query: { email: new Email(email) },
select: { _id: true },
props: { isRoot: true },
});
if (user && user.id) {
query.userId = user.id;
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}, found user with id: ${user.id}`,
);
} else {
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}, user not found for email: ${email}`,
);
return Response.sendJsonObjectResponse(
req,
res,
generateUsersListResponse([], startIndex, 0),
);
}
} else {
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}, invalid email format in filter: ${email}`,
);
return Response.sendJsonObjectResponse(
req,
res,
generateUsersListResponse([], startIndex, 0),
);
}
}
}
}
logger.debug(
`Project SCIM Users list - scimId: ${req.params["projectScimId"]!}, query built for projectId: ${projectId}`,
);
// Get team members
const teamMembers: Array<TeamMember> = await TeamMemberService.findBy({
query: query,
limit: LIMIT_MAX,
skip: 0,
props: { isRoot: true },
select: {
userId: true,
user: {
_id: true,
email: true,
name: true,
createdAt: true,
updatedAt: true,
},
},
});
// now get unique users.
const usersInProjects: Array<JSONObject> = teamMembers
.filter((tm: TeamMember) => {
return tm.user && tm.user.id;
})
.map((tm: TeamMember) => {
return formatUserForSCIM(
tm.user!,
req,
req.params["projectScimId"]!,
"project",
);
});
// remove duplicates
const uniqueUserIds: Set<string> = new Set<string>();
const users: Array<JSONObject> = usersInProjects.filter(
(user: JSONObject) => {
if (uniqueUserIds.has(user["id"]?.toString() || "")) {
return false;
}
uniqueUserIds.add(user["id"]?.toString() || "");
return true;
},
);
// now paginate the results
const paginatedUsers: Array<JSONObject> = users.slice(
(startIndex - 1) * count,
startIndex * count,
);
logger.debug(`SCIM Users response prepared with ${users.length} users`);
return Response.sendJsonObjectResponse(
req,
res,
generateUsersListResponse(paginatedUsers, startIndex, users.length),
);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Get Individual User - GET /scim/v2/Users/{id}
router.get(
"/scim/v2/:projectScimId/Users/:userId",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`SCIM Get individual user request for userId: ${req.params["userId"]}, projectScimId: ${req.params["projectScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const projectId: ObjectID = bearerData["projectId"] as ObjectID;
const userId: string = req.params["userId"]!;
logger.debug(
`SCIM Get user - projectId: ${projectId}, userId: ${userId}`,
);
if (!userId) {
throw new BadRequestException("User ID is required");
}
// Check if user exists and is part of the project
const projectUser: TeamMember | null = await TeamMemberService.findOneBy({
query: {
projectId: projectId,
userId: new ObjectID(userId),
},
select: {
userId: true,
user: {
_id: true,
email: true,
name: true,
createdAt: true,
updatedAt: true,
},
},
props: { isRoot: true },
});
if (!projectUser || !projectUser.user) {
logger.debug(
`SCIM Get user - user not found or not part of project for userId: ${userId}`,
);
throw new NotFoundException(
"User not found or not part of this project",
);
}
logger.debug(`SCIM Get user - found user: ${projectUser.user.id}`);
const user: JSONObject = formatUserForSCIM(
projectUser.user,
req,
req.params["projectScimId"]!,
"project",
);
return Response.sendJsonObjectResponse(req, res, user);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Update User - PUT /scim/v2/Users/{id}
router.put(
"/scim/v2/:projectScimId/Users/:userId",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`SCIM Update user request for userId: ${req.params["userId"]}, projectScimId: ${req.params["projectScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const projectId: ObjectID = bearerData["projectId"] as ObjectID;
const userId: string = req.params["userId"]!;
const scimUser: JSONObject = req.body;
logger.debug(
`SCIM Update user - projectId: ${projectId}, userId: ${userId}`,
);
logger.debug(
`Request body for SCIM Update user: ${JSON.stringify(scimUser, null, 2)}`,
);
if (!userId) {
throw new BadRequestException("User ID is required");
}
// Check if user exists and is part of the project
const projectUser: TeamMember | null = await TeamMemberService.findOneBy({
query: {
projectId: projectId,
userId: new ObjectID(userId),
},
select: {
userId: true,
user: {
_id: true,
email: true,
name: true,
createdAt: true,
updatedAt: true,
},
},
props: { isRoot: true },
});
if (!projectUser || !projectUser.user) {
logger.debug(
`SCIM Update user - user not found or not part of project for userId: ${userId}`,
);
throw new NotFoundException(
"User not found or not part of this project",
);
}
// Update user information
const email: string =
(scimUser["userName"] as string) ||
((scimUser["emails"] as JSONObject[])?.[0]?.["value"] as string);
const name: string = parseNameFromSCIM(scimUser);
const active: boolean = scimUser["active"] as boolean;
logger.debug(
`SCIM Update user - email: ${email}, name: ${name}, active: ${active}`,
);
// Handle user deactivation by removing from teams
if (active === false) {
logger.debug(
`SCIM Update user - user marked as inactive, removing from teams`,
);
const scimConfig: ProjectSCIM = bearerData["scimConfig"] as ProjectSCIM;
await handleUserTeamOperations(
"remove",
projectId,
new ObjectID(userId),
scimConfig,
);
logger.debug(
`SCIM Update user - user successfully removed from teams due to deactivation`,
);
}
// Handle user activation by adding to teams
if (active === true) {
logger.debug(
`SCIM Update user - user marked as active, adding to teams`,
);
const scimConfig: ProjectSCIM = bearerData["scimConfig"] as ProjectSCIM;
await handleUserTeamOperations(
"add",
projectId,
new ObjectID(userId),
scimConfig,
);
logger.debug(
`SCIM Update user - user successfully added to teams due to activation`,
);
}
if (email || name) {
const updateData: any = {};
if (email) {
updateData.email = new Email(email);
}
if (name) {
updateData.name = new Name(name);
}
logger.debug(
`SCIM Update user - updating user with data: ${JSON.stringify(updateData)}`,
);
await UserService.updateOneById({
id: new ObjectID(userId),
data: updateData,
props: { isRoot: true },
});
logger.debug(`SCIM Update user - user updated successfully`);
// Fetch updated user
const updatedUser: User | null = await UserService.findOneById({
id: new ObjectID(userId),
select: {
_id: true,
email: true,
name: true,
createdAt: true,
updatedAt: true,
},
props: { isRoot: true },
});
if (updatedUser) {
const user: JSONObject = formatUserForSCIM(
updatedUser,
req,
req.params["projectScimId"]!,
"project",
);
return Response.sendJsonObjectResponse(req, res, user);
}
}
logger.debug(
`SCIM Update user - no updates made, returning existing user`,
);
// If no updates were made, return the existing user
const user: JSONObject = formatUserForSCIM(
projectUser.user,
req,
req.params["projectScimId"]!,
"project",
);
return Response.sendJsonObjectResponse(req, res, user);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Groups endpoint - GET /scim/v2/Groups
router.get(
"/scim/v2/:projectScimId/Groups",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`SCIM Groups list request for projectScimId: ${req.params["projectScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const scimConfig: ProjectSCIM = bearerData["scimConfig"] as ProjectSCIM;
logger.debug(
`SCIM Groups - found ${scimConfig.teams?.length || 0} configured teams`,
);
// Return configured teams as groups
const groups: JSONObject[] = (scimConfig.teams || []).map((team: any) => {
return {
schemas: ["urn:ietf:params:scim:schemas:core:2.0:Group"],
id: team.id?.toString(),
displayName: team.name?.toString(),
members: [],
meta: {
resourceType: "Group",
location: `${req.protocol}://${req.get("host")}/scim/v2/${req.params["projectScimId"]}/Groups/${team.id?.toString()}`,
},
};
});
return Response.sendJsonObjectResponse(req, res, {
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
totalResults: groups.length,
startIndex: 1,
itemsPerPage: groups.length,
Resources: groups,
});
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Create User - POST /scim/v2/Users
router.post(
"/scim/v2/:projectScimId/Users",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`SCIM Create user request for projectScimId: ${req.params["projectScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const projectId: ObjectID = bearerData["projectId"] as ObjectID;
const scimConfig: ProjectSCIM = bearerData["scimConfig"] as ProjectSCIM;
if (!scimConfig.autoProvisionUsers) {
throw new BadRequestException(
"Auto-provisioning is disabled for this project",
);
}
const scimUser: JSONObject = req.body;
const email: string =
(scimUser["userName"] as string) ||
((scimUser["emails"] as JSONObject[])?.[0]?.["value"] as string);
const name: string = parseNameFromSCIM(scimUser);
logger.debug(`SCIM Create user - email: ${email}, name: ${name}`);
if (!email) {
throw new BadRequestException("userName or email is required");
}
// Check if user already exists
let user: User | null = await UserService.findOneBy({
query: { email: new Email(email) },
select: {
_id: true,
email: true,
name: true,
createdAt: true,
updatedAt: true,
},
props: { isRoot: true },
});
// Create user if doesn't exist
if (!user) {
logger.debug(
`SCIM Create user - creating new user for email: ${email}`,
);
user = await UserService.createByEmail({
email: new Email(email),
name: name ? new Name(name) : new Name("Unknown"),
isEmailVerified: true,
generateRandomPassword: true,
props: { isRoot: true },
});
} else {
logger.debug(
`SCIM Create user - user already exists with id: ${user.id}`,
);
}
// Add user to default teams if configured
if (scimConfig.teams && scimConfig.teams.length > 0) {
logger.debug(
`SCIM Create user - adding user to ${scimConfig.teams.length} configured teams`,
);
await handleUserTeamOperations("add", projectId, user.id!, scimConfig);
}
const createdUser: JSONObject = formatUserForSCIM(
user,
req,
req.params["projectScimId"]!,
"project",
);
logger.debug(
`SCIM Create user - returning created user with id: ${user.id}`,
);
res.status(201);
return Response.sendJsonObjectResponse(req, res, createdUser);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Delete User - DELETE /scim/v2/Users/{id}
router.delete(
"/scim/v2/:projectScimId/Users/:userId",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`SCIM Delete user request for userId: ${req.params["userId"]}, projectScimId: ${req.params["projectScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const projectId: ObjectID = bearerData["projectId"] as ObjectID;
const scimConfig: ProjectSCIM = bearerData["scimConfig"] as ProjectSCIM;
const userId: string = req.params["userId"]!;
if (!scimConfig.autoDeprovisionUsers) {
logger.debug("SCIM Delete user - auto-deprovisioning is disabled");
throw new BadRequestException(
"Auto-deprovisioning is disabled for this project",
);
}
if (!userId) {
throw new BadRequestException("User ID is required");
}
logger.debug(
`SCIM Delete user - removing user from all teams in project: ${projectId}`,
);
// Remove user from teams the SCIM configured
if (!scimConfig.teams || scimConfig.teams.length === 0) {
logger.debug("SCIM Delete user - no teams configured for SCIM");
throw new BadRequestException("No teams configured for SCIM");
}
await handleUserTeamOperations(
"remove",
projectId,
new ObjectID(userId),
scimConfig,
);
logger.debug(
`SCIM Delete user - user successfully deprovisioned from project`,
);
res.status(204);
return Response.sendJsonObjectResponse(req, res, {
message: "User deprovisioned",
});
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
export default router;

View File

@@ -168,6 +168,7 @@ router.post(
},
{
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
).catch((err: Error) => {
logger.error(err);
@@ -306,6 +307,7 @@ router.post(
},
{
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
).catch((err: Error) => {
logger.error(err);

View File

@@ -0,0 +1,570 @@
import SCIMMiddleware from "Common/Server/Middleware/SCIMAuthorization";
import StatusPagePrivateUserService from "Common/Server/Services/StatusPagePrivateUserService";
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
OneUptimeRequest,
} from "Common/Server/Utils/Express";
import Response from "Common/Server/Utils/Response";
import logger from "Common/Server/Utils/Logger";
import ObjectID from "Common/Types/ObjectID";
import Email from "Common/Types/Email";
import { JSONObject } from "Common/Types/JSON";
import StatusPagePrivateUser from "Common/Models/DatabaseModels/StatusPagePrivateUser";
import StatusPageSCIM from "Common/Models/DatabaseModels/StatusPageSCIM";
import BadRequestException from "Common/Types/Exception/BadRequestException";
import NotFoundException from "Common/Types/Exception/NotFoundException";
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
import {
formatUserForSCIM,
generateServiceProviderConfig,
} from "../Utils/SCIMUtils";
import Text from "Common/Types/Text";
import HashedString from "Common/Types/HashedString";
const router: ExpressRouter = Express.getRouter();
// SCIM Service Provider Configuration - GET /status-page-scim/v2/ServiceProviderConfig
router.get(
"/status-page-scim/v2/:statusPageScimId/ServiceProviderConfig",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Status Page SCIM ServiceProviderConfig - scimId: ${req.params["statusPageScimId"]!}`,
);
const serviceProviderConfig: JSONObject = generateServiceProviderConfig(
req,
req.params["statusPageScimId"]!,
"status-page",
);
return Response.sendJsonObjectResponse(req, res, serviceProviderConfig);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Status Page Users endpoint - GET /status-page-scim/v2/Users
router.get(
"/status-page-scim/v2/:statusPageScimId/Users",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Status Page SCIM Users list request for statusPageScimId: ${req.params["statusPageScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const statusPageId: ObjectID = bearerData["statusPageId"] as ObjectID;
// Parse query parameters
const startIndex: number =
parseInt(req.query["startIndex"] as string) || 1;
const count: number = Math.min(
parseInt(req.query["count"] as string) || 100,
LIMIT_PER_PROJECT,
);
const filter: string = req.query["filter"] as string;
logger.debug(
`Status Page SCIM Users - statusPageId: ${statusPageId}, startIndex: ${startIndex}, count: ${count}, filter: ${filter || "none"}`,
);
// Build query for status page users
const query: any = {
statusPageId: statusPageId,
};
// Handle SCIM filter for userName
if (filter) {
const emailMatch: RegExpMatchArray | null = filter.match(
/userName eq "([^"]+)"/i,
);
if (emailMatch) {
const email: string = emailMatch[1]!;
logger.debug(
`Status Page SCIM Users list - statusPageScimId: ${req.params["statusPageScimId"]!}, filter by email: ${email}`,
);
if (email) {
if (Email.isValid(email)) {
query.email = new Email(email);
logger.debug(
`Status Page SCIM Users list - statusPageScimId: ${req.params["statusPageScimId"]!}, filtering by email: ${email}`,
);
} else {
logger.debug(
`Status Page SCIM Users list - statusPageScimId: ${req.params["statusPageScimId"]!}, invalid email format in filter: ${email}`,
);
return Response.sendJsonObjectResponse(req, res, {
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
totalResults: 0,
startIndex: startIndex,
itemsPerPage: 0,
Resources: [],
});
}
}
}
}
// Get all private users for this status page
const statusPageUsers: Array<StatusPagePrivateUser> =
await StatusPagePrivateUserService.findBy({
query: query,
select: {
_id: true,
email: true,
createdAt: true,
updatedAt: true,
},
skip: 0,
limit: LIMIT_MAX,
props: { isRoot: true },
});
logger.debug(
`Status Page SCIM Users - found ${statusPageUsers.length} users`,
);
// Format users for SCIM
const users: Array<JSONObject> = statusPageUsers.map(
(user: StatusPagePrivateUser) => {
return formatUserForSCIM(
user,
req,
req.params["statusPageScimId"]!,
"status-page",
);
},
);
// Paginate the results
const paginatedUsers: Array<JSONObject> = users.slice(
(startIndex - 1) * count,
startIndex * count,
);
logger.debug(
`Status Page SCIM Users response prepared with ${users.length} users`,
);
return Response.sendJsonObjectResponse(req, res, {
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
totalResults: users.length,
startIndex: startIndex,
itemsPerPage: paginatedUsers.length,
Resources: paginatedUsers,
});
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Get Individual Status Page User - GET /status-page-scim/v2/Users/{id}
router.get(
"/status-page-scim/v2/:statusPageScimId/Users/:userId",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Status Page SCIM Get individual user request for userId: ${req.params["userId"]}, statusPageScimId: ${req.params["statusPageScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const statusPageId: ObjectID = bearerData["statusPageId"] as ObjectID;
const userId: string = req.params["userId"]!;
logger.debug(
`Status Page SCIM Get user - statusPageId: ${statusPageId}, userId: ${userId}`,
);
if (!userId) {
throw new BadRequestException("User ID is required");
}
// Check if user exists and belongs to this status page
const statusPageUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
statusPageId: statusPageId,
_id: new ObjectID(userId),
},
select: {
_id: true,
email: true,
createdAt: true,
updatedAt: true,
},
props: { isRoot: true },
});
if (!statusPageUser) {
logger.debug(
`Status Page SCIM Get user - user not found for userId: ${userId}`,
);
throw new NotFoundException(
"User not found or not part of this status page",
);
}
const user: JSONObject = formatUserForSCIM(
statusPageUser,
req,
req.params["statusPageScimId"]!,
"status-page",
);
logger.debug(
`Status Page SCIM Get user - returning user with id: ${statusPageUser.id}`,
);
return Response.sendJsonObjectResponse(req, res, user);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Create Status Page User - POST /status-page-scim/v2/Users
router.post(
"/status-page-scim/v2/:statusPageScimId/Users",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Status Page SCIM Create user request for statusPageScimId: ${req.params["statusPageScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const statusPageId: ObjectID = bearerData["statusPageId"] as ObjectID;
const scimConfig: StatusPageSCIM = bearerData[
"scimConfig"
] as StatusPageSCIM;
if (!scimConfig.autoProvisionUsers) {
throw new BadRequestException(
"Auto-provisioning is disabled for this status page",
);
}
const scimUser: JSONObject = req.body;
logger.debug(
`Status Page SCIM Create user - statusPageId: ${statusPageId}`,
);
logger.debug(
`Request body for Status Page SCIM Create user: ${JSON.stringify(scimUser, null, 2)}`,
);
// Extract user data from SCIM payload
const email: string =
(scimUser["userName"] as string) ||
((scimUser["emails"] as JSONObject[])?.[0]?.["value"] as string);
if (!email) {
throw new BadRequestException("Email is required for user creation");
}
logger.debug(`Status Page SCIM Create user - email: ${email}`);
// Check if user already exists for this status page
let user: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
statusPageId: statusPageId,
email: new Email(email),
},
select: {
_id: true,
email: true,
createdAt: true,
updatedAt: true,
},
props: { isRoot: true },
});
if (!user) {
logger.debug(
`Status Page SCIM Create user - creating new user with email: ${email}`,
);
const privateUser: StatusPagePrivateUser = new StatusPagePrivateUser();
privateUser.statusPageId = statusPageId;
privateUser.email = new Email(email);
privateUser.password = new HashedString(Text.generateRandomText(32));
privateUser.projectId = bearerData["projectId"] as ObjectID;
// Create new status page private user
user = await StatusPagePrivateUserService.create({
data: privateUser as any,
props: { isRoot: true },
});
} else {
logger.debug(
`Status Page SCIM Create user - user already exists with id: ${user.id}`,
);
}
const createdUser: JSONObject = formatUserForSCIM(
user,
req,
req.params["statusPageScimId"]!,
"status-page",
);
logger.debug(
`Status Page SCIM Create user - returning created user with id: ${user.id}`,
);
res.status(201);
return Response.sendJsonObjectResponse(req, res, createdUser);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Update Status Page User - PUT /status-page-scim/v2/Users/{id}
router.put(
"/status-page-scim/v2/:statusPageScimId/Users/:userId",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Status Page SCIM Update user request for userId: ${req.params["userId"]}, statusPageScimId: ${req.params["statusPageScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const statusPageId: ObjectID = bearerData["statusPageId"] as ObjectID;
const userId: string = req.params["userId"]!;
const scimUser: JSONObject = req.body;
logger.debug(
`Status Page SCIM Update user - statusPageId: ${statusPageId}, userId: ${userId}`,
);
logger.debug(
`Request body for Status Page SCIM Update user: ${JSON.stringify(scimUser, null, 2)}`,
);
if (!userId) {
throw new BadRequestException("User ID is required");
}
// Check if user exists and belongs to this status page
const statusPageUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
statusPageId: statusPageId,
_id: new ObjectID(userId),
},
select: {
_id: true,
email: true,
createdAt: true,
updatedAt: true,
},
props: { isRoot: true },
});
if (!statusPageUser) {
logger.debug(
`Status Page SCIM Update user - user not found for userId: ${userId}`,
);
throw new NotFoundException(
"User not found or not part of this status page",
);
}
// Update user information
const email: string =
(scimUser["userName"] as string) ||
((scimUser["emails"] as JSONObject[])?.[0]?.["value"] as string);
const active: boolean = scimUser["active"] as boolean;
logger.debug(
`Status Page SCIM Update user - email: ${email}, active: ${active}`,
);
// Handle user deactivation by deleting from status page
if (active === false) {
logger.debug(
`Status Page SCIM Update user - user marked as inactive, removing from status page`,
);
const scimConfig: StatusPageSCIM = bearerData[
"scimConfig"
] as StatusPageSCIM;
if (scimConfig.autoDeprovisionUsers) {
await StatusPagePrivateUserService.deleteOneById({
id: new ObjectID(userId),
props: { isRoot: true },
});
logger.debug(
`Status Page SCIM Update user - user removed from status page`,
);
// Return empty response for deleted user
return Response.sendJsonObjectResponse(req, res, {});
}
}
// Prepare update data
const updateData: {
email?: Email;
} = {};
if (email && email !== statusPageUser.email?.toString()) {
updateData.email = new Email(email);
}
// Only update if there are changes
if (Object.keys(updateData).length > 0) {
logger.debug(
`Status Page SCIM Update user - updating user with data: ${JSON.stringify(updateData)}`,
);
await StatusPagePrivateUserService.updateOneById({
id: new ObjectID(userId),
data: updateData,
props: { isRoot: true },
});
logger.debug(
`Status Page SCIM Update user - user updated successfully`,
);
// Fetch updated user
const updatedUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneById({
id: new ObjectID(userId),
select: {
_id: true,
email: true,
createdAt: true,
updatedAt: true,
},
props: { isRoot: true },
});
if (updatedUser) {
const user: JSONObject = formatUserForSCIM(
updatedUser,
req,
req.params["statusPageScimId"]!,
"status-page",
);
return Response.sendJsonObjectResponse(req, res, user);
}
}
logger.debug(
`Status Page SCIM Update user - no updates made, returning existing user`,
);
// If no updates were made, return the existing user
const user: JSONObject = formatUserForSCIM(
statusPageUser,
req,
req.params["statusPageScimId"]!,
"status-page",
);
return Response.sendJsonObjectResponse(req, res, user);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
// Delete Status Page User - DELETE /status-page-scim/v2/Users/{id}
router.delete(
"/status-page-scim/v2/:statusPageScimId/Users/:userId",
SCIMMiddleware.isAuthorizedSCIMRequest,
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
logger.debug(
`Status Page SCIM Delete user request for userId: ${req.params["userId"]}, statusPageScimId: ${req.params["statusPageScimId"]}`,
);
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
const bearerData: JSONObject =
oneuptimeRequest.bearerTokenData as JSONObject;
const statusPageId: ObjectID = bearerData["statusPageId"] as ObjectID;
const scimConfig: StatusPageSCIM = bearerData[
"scimConfig"
] as StatusPageSCIM;
const userId: string = req.params["userId"]!;
if (!scimConfig.autoDeprovisionUsers) {
throw new BadRequestException(
"Auto-deprovisioning is disabled for this status page",
);
}
logger.debug(
`Status Page SCIM Delete user - statusPageId: ${statusPageId}, userId: ${userId}`,
);
if (!userId) {
throw new BadRequestException("User ID is required");
}
// Check if user exists and belongs to this status page
const statusPageUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
statusPageId: statusPageId,
_id: new ObjectID(userId),
},
select: {
_id: true,
},
props: { isRoot: true },
});
if (!statusPageUser) {
logger.debug(
`Status Page SCIM Delete user - user not found for userId: ${userId}`,
);
// SCIM spec says to return 404 for non-existent resources
throw new NotFoundException("User not found");
}
// Delete the user from status page
await StatusPagePrivateUserService.deleteOneById({
id: new ObjectID(userId),
props: { isRoot: true },
});
logger.debug(
`Status Page SCIM Delete user - user deleted successfully for userId: ${userId}`,
);
// Return 204 No Content for successful deletion
res.status(204);
return Response.sendEmptySuccessResponse(req, res);
} catch (err) {
logger.error(err);
return Response.sendErrorResponse(req, res, err as BadRequestException);
}
},
);
export default router;

View File

@@ -1,8 +1,10 @@
import AuthenticationAPI from "./API/Authentication";
import ResellerAPI from "./API/Reseller";
import SsoAPI from "./API/SSO";
import SCIMAPI from "./API/SCIM";
import StatusPageAuthenticationAPI from "./API/StatusPageAuthentication";
import StatusPageSsoAPI from "./API/StatusPageSSO";
import StatusPageSCIMAPI from "./API/StatusPageSCIM";
import FeatureSet from "Common/Server/Types/FeatureSet";
import Express, { ExpressApplication } from "Common/Server/Utils/Express";
import "ejs";
@@ -19,6 +21,10 @@ const IdentityFeatureSet: FeatureSet = {
app.use([`/${APP_NAME}`, "/"], SsoAPI);
app.use([`/${APP_NAME}`, "/"], SCIMAPI);
app.use([`/${APP_NAME}`, "/"], StatusPageSCIMAPI);
app.use([`/${APP_NAME}`, "/"], StatusPageSsoAPI);
app.use(

View File

@@ -0,0 +1,244 @@
import { ExpressRequest } from "Common/Server/Utils/Express";
import logger from "Common/Server/Utils/Logger";
import { JSONObject } from "Common/Types/JSON";
import Email from "Common/Types/Email";
import Name from "Common/Types/Name";
import ObjectID from "Common/Types/ObjectID";
/**
* Shared SCIM utility functions for both Project SCIM and Status Page SCIM
*/
// Base interface for SCIM user-like objects - compatible with User model
export interface SCIMUser {
id?: ObjectID | null;
email?: Email;
name?: Name | string;
createdAt?: Date;
updatedAt?: Date;
}
/**
* Parse name information from SCIM user payload
*/
export const parseNameFromSCIM: (scimUser: JSONObject) => string = (
scimUser: JSONObject,
): string => {
logger.debug(
`SCIM - Parsing name from SCIM user: ${JSON.stringify(scimUser, null, 2)}`,
);
const givenName: string =
((scimUser["name"] as JSONObject)?.["givenName"] as string) || "";
const familyName: string =
((scimUser["name"] as JSONObject)?.["familyName"] as string) || "";
const formattedName: string = (scimUser["name"] as JSONObject)?.[
"formatted"
] as string;
// Construct full name: prefer formatted, then combine given+family, then fallback to displayName
if (formattedName) {
return formattedName;
} else if (givenName || familyName) {
return `${givenName} ${familyName}`.trim();
} else if (scimUser["displayName"]) {
return scimUser["displayName"] as string;
}
return "";
};
/**
* Parse full name into SCIM name format
*/
export const parseNameToSCIMFormat: (fullName: string) => {
givenName: string;
familyName: string;
formatted: string;
} = (
fullName: string,
): { givenName: string; familyName: string; formatted: string } => {
const nameParts: string[] = fullName.trim().split(/\s+/);
const givenName: string = nameParts[0] || "";
const familyName: string = nameParts.slice(1).join(" ") || "";
return {
givenName,
familyName,
formatted: fullName,
};
};
/**
* Format user object for SCIM response
*/
export const formatUserForSCIM: (
user: SCIMUser,
req: ExpressRequest,
scimId: string,
scimType: "project" | "status-page",
) => JSONObject = (
user: SCIMUser,
req: ExpressRequest,
scimId: string,
scimType: "project" | "status-page",
): JSONObject => {
const baseUrl: string = `${req.protocol}://${req.get("host")}`;
const userName: string = user.email?.toString() || "";
const fullName: string =
user.name?.toString() || userName.split("@")[0] || "Unknown User";
const nameData: { givenName: string; familyName: string; formatted: string } =
parseNameToSCIMFormat(fullName);
// Determine the correct endpoint path based on SCIM type
const endpointPath: string =
scimType === "project"
? `/scim/v2/${scimId}/Users/${user.id?.toString()}`
: `/status-page-scim/v2/${scimId}/Users/${user.id?.toString()}`;
return {
schemas: ["urn:ietf:params:scim:schemas:core:2.0:User"],
id: user.id?.toString(),
userName: userName,
displayName: nameData.formatted,
name: {
formatted: nameData.formatted,
familyName: nameData.familyName,
givenName: nameData.givenName,
},
emails: [
{
value: userName,
type: "work",
primary: true,
},
],
active: true,
meta: {
resourceType: "User",
created: user.createdAt?.toISOString(),
lastModified: user.updatedAt?.toISOString(),
location: `${baseUrl}${endpointPath}`,
},
};
};
/**
* Extract email from SCIM user payload
*/
export const extractEmailFromSCIM: (scimUser: JSONObject) => string = (
scimUser: JSONObject,
): string => {
return (
(scimUser["userName"] as string) ||
((scimUser["emails"] as JSONObject[])?.[0]?.["value"] as string) ||
""
);
};
/**
* Extract active status from SCIM user payload
*/
export const extractActiveFromSCIM: (scimUser: JSONObject) => boolean = (
scimUser: JSONObject,
): boolean => {
return scimUser["active"] !== false; // Default to true if not specified
};
/**
* Generate SCIM ServiceProviderConfig response
*/
export const generateServiceProviderConfig: (
req: ExpressRequest,
scimId: string,
scimType: "project" | "status-page",
documentationUrl?: string,
) => JSONObject = (
req: ExpressRequest,
scimId: string,
scimType: "project" | "status-page",
documentationUrl: string = "https://oneuptime.com/docs/identity/scim",
): JSONObject => {
const baseUrl: string = `${req.protocol}://${req.get("host")}`;
const endpointPath: string =
scimType === "project"
? `/scim/v2/${scimId}`
: `/status-page-scim/v2/${scimId}`;
return {
schemas: ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
documentationUri: documentationUrl,
patch: {
supported: true,
},
bulk: {
supported: true,
maxOperations: 1000,
maxPayloadSize: 1048576,
},
filter: {
supported: true,
maxResults: 200,
},
changePassword: {
supported: false,
},
sort: {
supported: true,
},
etag: {
supported: false,
},
authenticationSchemes: [
{
type: "httpbearer",
name: "HTTP Bearer",
description: "Authentication scheme using HTTP Bearer Token",
primary: true,
},
],
meta: {
location: `${baseUrl}${endpointPath}/ServiceProviderConfig`,
resourceType: "ServiceProviderConfig",
created: "2023-01-01T00:00:00Z",
lastModified: "2023-01-01T00:00:00Z",
},
};
};
/**
* Generate SCIM ListResponse for users
*/
export const generateUsersListResponse: (
users: JSONObject[],
startIndex: number,
totalResults: number,
) => JSONObject = (
users: JSONObject[],
startIndex: number,
totalResults: number,
): JSONObject => {
return {
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
totalResults: totalResults,
startIndex: startIndex,
itemsPerPage: users.length,
Resources: users,
};
};
/**
* Parse query parameters for SCIM list requests
*/
export const parseSCIMQueryParams: (req: ExpressRequest) => {
startIndex: number;
count: number;
} = (req: ExpressRequest): { startIndex: number; count: number } => {
const startIndex: number = parseInt(req.query["startIndex"] as string) || 1;
const count: number = Math.min(
parseInt(req.query["count"] as string) || 100,
200, // SCIM recommended max
);
return { startIndex, count };
};

View File

@@ -67,7 +67,6 @@
<link rel="apple-touch-icon-precomposed" href="/img/ou-wb.svg">
<link rel="icon" href="/img/ou-wb.svg">
<link rel="image_src" type="image/png" href="/img/hou-wb.svg">
<link rel="canonical" href="/">
<link rel="manifest" href="/manifest.json">
<meta property="og:title" content="OneUptime - One Complete Observability platform.">
<meta property="og:url" content="https://oneuptime.com">

View File

@@ -31,6 +31,22 @@ router.post(
userOnCallLogTimelineId:
(body["userOnCallLogTimelineId"] as ObjectID) || undefined,
customTwilioConfig: body["customTwilioConfig"] as any,
incidentId: (body["incidentId"] as ObjectID) || undefined,
alertId: (body["alertId"] as ObjectID) || undefined,
scheduledMaintenanceId:
(body["scheduledMaintenanceId"] as ObjectID) || undefined,
statusPageId: (body["statusPageId"] as ObjectID) || undefined,
statusPageAnnouncementId:
(body["statusPageAnnouncementId"] as ObjectID) || undefined,
userId: (body["userId"] as ObjectID) || undefined,
onCallPolicyId: (body["onCallPolicyId"] as ObjectID) || undefined,
onCallPolicyEscalationRuleId:
(body["onCallPolicyEscalationRuleId"] as ObjectID) || undefined,
onCallDutyPolicyExecutionLogTimelineId:
(body["onCallDutyPolicyExecutionLogTimelineId"] as ObjectID) ||
undefined,
onCallScheduleId: (body["onCallScheduleId"] as ObjectID) || undefined,
teamId: (body["teamId"] as ObjectID) || undefined,
});
return Response.sendEmptySuccessResponse(req, res);

View File

@@ -43,6 +43,43 @@ router.post(
emailServer: mailServer,
userOnCallLogTimelineId:
(body["userOnCallLogTimelineId"] as ObjectID) || undefined,
incidentId: body["incidentId"]
? new ObjectID(body["incidentId"].toString())
: undefined,
alertId: body["alertId"]
? new ObjectID(body["alertId"].toString())
: undefined,
scheduledMaintenanceId: body["scheduledMaintenanceId"]
? new ObjectID(body["scheduledMaintenanceId"].toString())
: undefined,
statusPageId: body["statusPageId"]
? new ObjectID(body["statusPageId"].toString())
: undefined,
statusPageAnnouncementId: body["statusPageAnnouncementId"]
? new ObjectID(body["statusPageAnnouncementId"].toString())
: undefined,
userId: body["userId"]
? new ObjectID(body["userId"].toString())
: undefined,
onCallPolicyId: body["onCallPolicyId"]
? new ObjectID(body["onCallPolicyId"].toString())
: undefined,
onCallPolicyEscalationRuleId: body["onCallPolicyEscalationRuleId"]
? new ObjectID(body["onCallPolicyEscalationRuleId"].toString())
: undefined,
onCallDutyPolicyExecutionLogTimelineId: body[
"onCallDutyPolicyExecutionLogTimelineId"
]
? new ObjectID(
body["onCallDutyPolicyExecutionLogTimelineId"].toString(),
)
: undefined,
onCallScheduleId: body["onCallScheduleId"]
? new ObjectID(body["onCallScheduleId"].toString())
: undefined,
teamId: body["teamId"]
? new ObjectID(body["teamId"].toString())
: undefined,
});
return Response.sendEmptySuccessResponse(req, res);

View File

@@ -0,0 +1,65 @@
import PushService from "../Services/PushNotificationService";
import ClusterKeyAuthorization from "Common/Server/Middleware/ClusterKeyAuthorization";
import ObjectID from "Common/Types/ObjectID";
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
} from "Common/Server/Utils/Express";
import Response from "Common/Server/Utils/Response";
import { JSONObject } from "Common/Types/JSON";
import JSONFunctions from "Common/Types/JSONFunctions";
const router: ExpressRouter = Express.getRouter();
router.post(
"/send",
ClusterKeyAuthorization.isAuthorizedServiceMiddleware,
async (req: ExpressRequest, res: ExpressResponse) => {
const body: JSONObject = JSONFunctions.deserialize(req.body);
// Support both new devices format and legacy deviceTokens/deviceNames format
let devices: Array<{ token: string; name?: string }> = [];
if (body["devices"]) {
// New format: devices as array of objects
devices = body["devices"] as Array<{ token: string; name?: string }>;
} else {
throw new Error("Invalid request format: 'devices' array is required.");
}
await PushService.send(
{
devices,
deviceType: (body["deviceType"] as any) || "web",
message: body["message"] as any,
},
{
projectId: (body["projectId"] as ObjectID) || undefined,
isSensitive: (body["isSensitive"] as boolean) || false,
userOnCallLogTimelineId:
(body["userOnCallLogTimelineId"] as ObjectID) || undefined,
incidentId: (body["incidentId"] as ObjectID) || undefined,
alertId: (body["alertId"] as ObjectID) || undefined,
scheduledMaintenanceId:
(body["scheduledMaintenanceId"] as ObjectID) || undefined,
statusPageId: (body["statusPageId"] as ObjectID) || undefined,
statusPageAnnouncementId:
(body["statusPageAnnouncementId"] as ObjectID) || undefined,
userId: (body["userId"] as ObjectID) || undefined,
onCallPolicyId: (body["onCallPolicyId"] as ObjectID) || undefined,
onCallPolicyEscalationRuleId:
(body["onCallPolicyEscalationRuleId"] as ObjectID) || undefined,
onCallDutyPolicyExecutionLogTimelineId:
(body["onCallDutyPolicyExecutionLogTimelineId"] as ObjectID) ||
undefined,
onCallScheduleId: (body["onCallScheduleId"] as ObjectID) || undefined,
teamId: (body["teamId"] as ObjectID) || undefined,
},
);
return Response.sendEmptySuccessResponse(req, res);
},
);
export default router;

View File

@@ -30,6 +30,22 @@ router.post(
userOnCallLogTimelineId:
(body["userOnCallLogTimelineId"] as ObjectID) || undefined,
customTwilioConfig: body["customTwilioConfig"] as any,
incidentId: (body["incidentId"] as ObjectID) || undefined,
alertId: (body["alertId"] as ObjectID) || undefined,
scheduledMaintenanceId:
(body["scheduledMaintenanceId"] as ObjectID) || undefined,
statusPageId: (body["statusPageId"] as ObjectID) || undefined,
statusPageAnnouncementId:
(body["statusPageAnnouncementId"] as ObjectID) || undefined,
userId: (body["userId"] as ObjectID) || undefined,
onCallPolicyId: (body["onCallPolicyId"] as ObjectID) || undefined,
onCallPolicyEscalationRuleId:
(body["onCallPolicyEscalationRuleId"] as ObjectID) || undefined,
onCallDutyPolicyExecutionLogTimelineId:
(body["onCallDutyPolicyExecutionLogTimelineId"] as ObjectID) ||
undefined,
onCallScheduleId: (body["onCallScheduleId"] as ObjectID) || undefined,
teamId: (body["teamId"] as ObjectID) || undefined,
});
return Response.sendEmptySuccessResponse(req, res);

View File

@@ -2,6 +2,7 @@ import CallAPI from "./API/Call";
// API
import MailAPI from "./API/Mail";
import SmsAPI from "./API/SMS";
import PushNotificationAPI from "./API/PushNotification";
import SMTPConfigAPI from "./API/SMTPConfig";
import "./Utils/Handlebars";
import FeatureSet from "Common/Server/Types/FeatureSet";
@@ -15,6 +16,7 @@ const NotificationFeatureSet: FeatureSet = {
app.use([`/${APP_NAME}/email`, "/email"], MailAPI);
app.use([`/${APP_NAME}/sms`, "/sms"], SmsAPI);
app.use([`/${APP_NAME}/push`, "/push"], PushNotificationAPI);
app.use([`/${APP_NAME}/call`, "/call"], CallAPI);
app.use([`/${APP_NAME}/smtp-config`, "/smtp-config"], SMTPConfigAPI);
},

View File

@@ -28,6 +28,36 @@ import Twilio from "twilio";
import { CallInstance } from "twilio/lib/rest/api/v2010/account/call";
import Phone from "Common/Types/Phone";
/**
* Extracts the main sayMessage values from a CallRequest's data array for call summary.
* Excludes acknowledgment responses, error messages, and other system messages.
* @param callRequest The call request containing data array with various objects
* @returns A string containing main call content messages separated by newlines
*/
function extractSayMessagesFromCallRequest(callRequest: CallRequest): string {
const sayMessages: string[] = [];
if (callRequest.data && Array.isArray(callRequest.data)) {
for (const item of callRequest.data) {
// Check if the item is a Say object with sayMessage
if ((item as Say).sayMessage) {
sayMessages.push((item as Say).sayMessage);
}
// Check if the item is a GatherInput with introMessage
if ((item as GatherInput).introMessage) {
sayMessages.push((item as GatherInput).introMessage);
}
// NOTE: Excluding noInputMessage and onInputCallRequest messages from summary
// as they contain system responses like "Good bye", "Invalid input", "You have acknowledged"
// which should not be included in the call summary according to user requirements
}
}
return sayMessages.length > 0
? sayMessages.join(" ")
: "No message content found";
}
export default class CallService {
public static async makeCall(
callRequest: CallRequest,
@@ -36,6 +66,18 @@ export default class CallService {
isSensitive?: boolean; // if true, message will not be logged
userOnCallLogTimelineId?: ObjectID | undefined; // user notification log timeline id
customTwilioConfig?: TwilioConfig | undefined;
incidentId?: ObjectID | undefined;
alertId?: ObjectID | undefined;
scheduledMaintenanceId?: ObjectID | undefined;
statusPageId?: ObjectID | undefined;
statusPageAnnouncementId?: ObjectID | undefined;
userId?: ObjectID | undefined;
// On-call policy related fields
onCallPolicyId?: ObjectID | undefined;
onCallPolicyEscalationRuleId?: ObjectID | undefined;
onCallDutyPolicyExecutionLogTimelineId?: ObjectID | undefined;
onCallScheduleId?: ObjectID | undefined;
teamId?: ObjectID | undefined;
},
): Promise<void> {
let callError: Error | null = null;
@@ -82,14 +124,58 @@ export default class CallService {
callLog.fromNumber = fromNumber;
callLog.callData =
options && options.isSensitive
? { message: "This call is sensitive and is not logged" }
: JSON.parse(JSON.stringify(callRequest));
? ({ message: "This call is sensitive and is not logged" } as any)
: ({
message: extractSayMessagesFromCallRequest(callRequest),
} as any);
callLog.callCostInUSDCents = 0;
if (options.projectId) {
callLog.projectId = options.projectId;
}
if (options.incidentId) {
callLog.incidentId = options.incidentId;
}
if (options.alertId) {
callLog.alertId = options.alertId;
}
if (options.scheduledMaintenanceId) {
callLog.scheduledMaintenanceId = options.scheduledMaintenanceId;
}
if (options.statusPageId) {
callLog.statusPageId = options.statusPageId;
}
if (options.statusPageAnnouncementId) {
callLog.statusPageAnnouncementId = options.statusPageAnnouncementId;
}
if (options.userId) {
callLog.userId = options.userId;
}
if (options.teamId) {
callLog.teamId = options.teamId;
}
// Set OnCall-related fields
if (options.onCallPolicyId) {
callLog.onCallDutyPolicyId = options.onCallPolicyId;
}
if (options.onCallPolicyEscalationRuleId) {
callLog.onCallDutyPolicyEscalationRuleId =
options.onCallPolicyEscalationRuleId;
}
if (options.onCallScheduleId) {
callLog.onCallDutyPolicyScheduleId = options.onCallScheduleId;
}
let project: Project | null = null;
// make sure project has enough balance.

View File

@@ -345,6 +345,18 @@ export default class MailService {
emailServer?: EmailServer | undefined;
userOnCallLogTimelineId?: ObjectID | undefined;
timeout?: number | undefined;
incidentId?: ObjectID | undefined;
alertId?: ObjectID | undefined;
scheduledMaintenanceId?: ObjectID | undefined;
statusPageId?: ObjectID | undefined;
statusPageAnnouncementId?: ObjectID | undefined;
userId?: ObjectID | undefined;
// On-call policy related fields
onCallPolicyId?: ObjectID | undefined;
onCallPolicyEscalationRuleId?: ObjectID | undefined;
onCallDutyPolicyExecutionLogTimelineId?: ObjectID | undefined;
onCallScheduleId?: ObjectID | undefined;
teamId?: ObjectID | undefined;
}
| undefined,
): Promise<void> {
@@ -359,6 +371,48 @@ export default class MailService {
if (options.emailServer?.id) {
emailLog.projectSmtpConfigId = options.emailServer?.id;
}
if (options.incidentId) {
emailLog.incidentId = options.incidentId;
}
if (options.alertId) {
emailLog.alertId = options.alertId;
}
if (options.scheduledMaintenanceId) {
emailLog.scheduledMaintenanceId = options.scheduledMaintenanceId;
}
if (options.statusPageId) {
emailLog.statusPageId = options.statusPageId;
}
if (options.statusPageAnnouncementId) {
emailLog.statusPageAnnouncementId = options.statusPageAnnouncementId;
}
if (options.userId) {
emailLog.userId = options.userId;
}
if (options.teamId) {
emailLog.teamId = options.teamId;
}
// Set OnCall-related fields
if (options.onCallPolicyId) {
emailLog.onCallDutyPolicyId = options.onCallPolicyId;
}
if (options.onCallPolicyEscalationRuleId) {
emailLog.onCallDutyPolicyEscalationRuleId =
options.onCallPolicyEscalationRuleId;
}
if (options.onCallScheduleId) {
emailLog.onCallDutyPolicyScheduleId = options.onCallScheduleId;
}
}
// default vars.

View File

@@ -0,0 +1,44 @@
import PushNotificationRequest from "Common/Types/PushNotification/PushNotificationRequest";
import ObjectID from "Common/Types/ObjectID";
import PushNotificationServiceCommon from "Common/Server/Services/PushNotificationService";
export default class PushNotificationService {
public static async send(
request: PushNotificationRequest,
options: {
projectId?: ObjectID | undefined;
isSensitive?: boolean;
userOnCallLogTimelineId?: ObjectID | undefined;
incidentId?: ObjectID | undefined;
alertId?: ObjectID | undefined;
scheduledMaintenanceId?: ObjectID | undefined;
statusPageId?: ObjectID | undefined;
statusPageAnnouncementId?: ObjectID | undefined;
userId?: ObjectID | undefined;
onCallPolicyId?: ObjectID | undefined;
onCallPolicyEscalationRuleId?: ObjectID | undefined;
onCallDutyPolicyExecutionLogTimelineId?: ObjectID | undefined;
onCallScheduleId?: ObjectID | undefined;
teamId?: ObjectID | undefined;
} = {},
): Promise<void> {
// Delegate to Common service which now handles logging and timeline updates
await PushNotificationServiceCommon.sendPushNotification(request, {
projectId: options.projectId,
isSensitive: Boolean(options.isSensitive),
userOnCallLogTimelineId: options.userOnCallLogTimelineId,
incidentId: options.incidentId,
alertId: options.alertId,
scheduledMaintenanceId: options.scheduledMaintenanceId,
statusPageId: options.statusPageId,
statusPageAnnouncementId: options.statusPageAnnouncementId,
userId: options.userId,
onCallPolicyId: options.onCallPolicyId,
onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
onCallDutyPolicyExecutionLogTimelineId:
options.onCallDutyPolicyExecutionLogTimelineId,
onCallScheduleId: options.onCallScheduleId,
teamId: options.teamId,
});
}
}

View File

@@ -31,6 +31,18 @@ export default class SmsService {
customTwilioConfig?: TwilioConfig | undefined;
isSensitive?: boolean; // if true, message will not be logged
userOnCallLogTimelineId?: ObjectID | undefined;
incidentId?: ObjectID | undefined;
alertId?: ObjectID | undefined;
scheduledMaintenanceId?: ObjectID | undefined;
statusPageId?: ObjectID | undefined;
statusPageAnnouncementId?: ObjectID | undefined;
userId?: ObjectID | undefined;
// On-call policy related fields
onCallPolicyId?: ObjectID | undefined;
onCallPolicyEscalationRuleId?: ObjectID | undefined;
onCallDutyPolicyExecutionLogTimelineId?: ObjectID | undefined;
onCallScheduleId?: ObjectID | undefined;
teamId?: ObjectID | undefined;
},
): Promise<void> {
let smsError: Error | null = null;
@@ -71,6 +83,48 @@ export default class SmsService {
smsLog.projectId = options.projectId;
}
if (options.incidentId) {
smsLog.incidentId = options.incidentId;
}
if (options.alertId) {
smsLog.alertId = options.alertId;
}
if (options.scheduledMaintenanceId) {
smsLog.scheduledMaintenanceId = options.scheduledMaintenanceId;
}
if (options.statusPageId) {
smsLog.statusPageId = options.statusPageId;
}
if (options.statusPageAnnouncementId) {
smsLog.statusPageAnnouncementId = options.statusPageAnnouncementId;
}
if (options.userId) {
smsLog.userId = options.userId;
}
if (options.teamId) {
smsLog.teamId = options.teamId;
}
// Set OnCall-related fields
if (options.onCallPolicyId) {
smsLog.onCallDutyPolicyId = options.onCallPolicyId;
}
if (options.onCallPolicyEscalationRuleId) {
smsLog.onCallDutyPolicyEscalationRuleId =
options.onCallPolicyEscalationRuleId;
}
if (options.onCallScheduleId) {
smsLog.onCallDutyPolicyScheduleId = options.onCallScheduleId;
}
const twilioConfig: TwilioConfig | null =
options.customTwilioConfig || (await getTwilioConfig());

View File

@@ -4,5 +4,13 @@
"ignore": [
"greenlock.d/*"
],
"exec": "node --inspect=0.0.0.0:9229 --require ts-node/register Index.ts"
"watchOptions": {
"useFsEvents": false,
"interval": 500
},
"env": {
"TS_NODE_TRANSPILE_ONLY": "1",
"TS_NODE_FILES": "false"
},
"exec": "node --inspect=0.0.0.0:9229 -r ts-node/register/transpile-only Index.ts"
}

1
App/package-lock.json generated
View File

@@ -76,6 +76,7 @@
"crypto-js": "^4.2.0",
"dotenv": "^16.4.4",
"ejs": "^3.1.10",
"elkjs": "^0.10.0",
"esbuild": "^0.25.5",
"express": "^4.21.1",
"formik": "^2.4.6",

View File

@@ -1,5 +1,14 @@
import Project from "./Project";
import Incident from "./Incident";
import Alert from "./Alert";
import ScheduledMaintenance from "./ScheduledMaintenance";
import StatusPage from "./StatusPage";
import StatusPageAnnouncement from "./StatusPageAnnouncement";
import User from "./User";
import OnCallDutyPolicy from "./OnCallDutyPolicy";
import OnCallDutyPolicyEscalationRule from "./OnCallDutyPolicyEscalationRule";
import OnCallDutyPolicySchedule from "./OnCallDutyPolicySchedule";
import Team from "./Team";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import CallStatus from "../../Types/Call/CallStatus";
@@ -256,6 +265,575 @@ export default class CallLog extends BaseModel {
})
public callCostInUSDCents?: number = undefined;
// Relations to resources that triggered this Call (nullable)
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "incidentId",
type: TableColumnType.Entity,
modelType: Incident,
title: "Incident",
description: "Incident associated with this Call (if any)",
})
@ManyToOne(
() => {
return Incident;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "incidentId" })
public incident?: Incident = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Incident ID",
description: "ID of Incident associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public incidentId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "userId",
type: TableColumnType.Entity,
modelType: User,
title: "User",
description: "User who initiated this Call (if any)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "userId" })
public user?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "User ID",
description: "ID of User who initiated this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public userId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "alertId",
type: TableColumnType.Entity,
modelType: Alert,
title: "Alert",
description: "Alert associated with this Call (if any)",
})
@ManyToOne(
() => {
return Alert;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "alertId" })
public alert?: Alert = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Alert ID",
description: "ID of Alert associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public alertId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "scheduledMaintenanceId",
type: TableColumnType.Entity,
modelType: ScheduledMaintenance,
title: "Scheduled Maintenance",
description: "Scheduled Maintenance associated with this Call (if any)",
})
@ManyToOne(
() => {
return ScheduledMaintenance;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "scheduledMaintenanceId" })
public scheduledMaintenance?: ScheduledMaintenance = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Scheduled Maintenance ID",
description:
"ID of Scheduled Maintenance associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public scheduledMaintenanceId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageId",
type: TableColumnType.Entity,
modelType: StatusPage,
title: "Status Page",
description: "Status Page associated with this Call (if any)",
})
@ManyToOne(
() => {
return StatusPage;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageId" })
public statusPage?: StatusPage = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page ID",
description: "ID of Status Page associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageAnnouncementId",
type: TableColumnType.Entity,
modelType: StatusPageAnnouncement,
title: "Status Page Announcement",
description: "Status Page Announcement associated with this Call (if any)",
})
@ManyToOne(
() => {
return StatusPageAnnouncement;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageAnnouncementId" })
public statusPageAnnouncement?: StatusPageAnnouncement = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page Announcement ID",
description:
"ID of Status Page Announcement associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageAnnouncementId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicy,
title: "On-Call Duty Policy",
description: "On-Call Duty Policy associated with this Call (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicy;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyId" })
public onCallDutyPolicy?: OnCallDutyPolicy = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy ID",
description: "ID of On-Call Duty Policy associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyEscalationRuleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicyEscalationRule,
title: "On-Call Duty Policy Escalation Rule",
description:
"On-Call Duty Policy Escalation Rule associated with this Call (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicyEscalationRule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyEscalationRuleId" })
public onCallDutyPolicyEscalationRule?: OnCallDutyPolicyEscalationRule =
undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Escalation Rule ID",
description:
"ID of On-Call Duty Policy Escalation Rule associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyEscalationRuleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyScheduleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicySchedule,
title: "On-Call Duty Policy Schedule",
description:
"On-Call Duty Policy Schedule associated with this Call (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicySchedule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyScheduleId" })
public onCallDutyPolicySchedule?: OnCallDutyPolicySchedule = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Schedule ID",
description:
"ID of On-Call Duty Policy Schedule associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyScheduleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "teamId",
type: TableColumnType.Entity,
modelType: Team,
title: "Team",
description: "Team associated with this Call (if any)",
})
@ManyToOne(
() => {
return Team;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "teamId" })
public team?: Team = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadCallLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Team ID",
description: "ID of Team associated with this Call (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public teamId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],

View File

@@ -729,6 +729,7 @@ export default class CopilotAction extends BaseModel {
type: TableColumnType.Boolean,
title: "Is Priority",
description: "Is Priority",
defaultValue: false,
})
@Column({
nullable: false,

View File

@@ -1,6 +1,15 @@
import Project from "./Project";
import Incident from "./Incident";
import Alert from "./Alert";
import ScheduledMaintenance from "./ScheduledMaintenance";
import StatusPage from "./StatusPage";
import ProjectSmtpConfig from "./ProjectSmtpConfig";
import StatusPageAnnouncement from "./StatusPageAnnouncement";
import User from "./User";
import OnCallDutyPolicy from "./OnCallDutyPolicy";
import OnCallDutyPolicyEscalationRule from "./OnCallDutyPolicyEscalationRule";
import OnCallDutyPolicySchedule from "./OnCallDutyPolicySchedule";
import Team from "./Team";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
@@ -289,6 +298,576 @@ export default class EmailLog extends BaseModel {
})
public projectSmtpConfigId?: ObjectID = undefined;
// Relations to resources that triggered this email (nullable)
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "incidentId",
type: TableColumnType.Entity,
modelType: Incident,
title: "Incident",
description: "Incident associated with this email (if any)",
})
@ManyToOne(
() => {
return Incident;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "incidentId" })
public incident?: Incident = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Incident ID",
description: "ID of Incident associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public incidentId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "userId",
type: TableColumnType.Entity,
modelType: User,
title: "User",
description: "User who initiated this email (if any)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "userId" })
public user?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "User ID",
description: "ID of User who initiated this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public userId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "alertId",
type: TableColumnType.Entity,
modelType: Alert,
title: "Alert",
description: "Alert associated with this email (if any)",
})
@ManyToOne(
() => {
return Alert;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "alertId" })
public alert?: Alert = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Alert ID",
description: "ID of Alert associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public alertId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "scheduledMaintenanceId",
type: TableColumnType.Entity,
modelType: ScheduledMaintenance,
title: "Scheduled Maintenance",
description: "Scheduled Maintenance associated with this email (if any)",
})
@ManyToOne(
() => {
return ScheduledMaintenance;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "scheduledMaintenanceId" })
public scheduledMaintenance?: ScheduledMaintenance = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Scheduled Maintenance ID",
description:
"ID of Scheduled Maintenance associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public scheduledMaintenanceId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageId",
type: TableColumnType.Entity,
modelType: StatusPage,
title: "Status Page",
description: "Status Page associated with this email (if any)",
})
@ManyToOne(
() => {
return StatusPage;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageId" })
public statusPage?: StatusPage = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page ID",
description: "ID of Status Page associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageAnnouncementId",
type: TableColumnType.Entity,
modelType: StatusPageAnnouncement,
title: "Status Page Announcement",
description: "Status Page Announcement associated with this email (if any)",
})
@ManyToOne(
() => {
return StatusPageAnnouncement;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageAnnouncementId" })
public statusPageAnnouncement?: StatusPageAnnouncement = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page Announcement ID",
description:
"ID of Status Page Announcement associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageAnnouncementId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicy,
title: "On-Call Duty Policy",
description: "On-Call Duty Policy associated with this email (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicy;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyId" })
public onCallDutyPolicy?: OnCallDutyPolicy = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy ID",
description:
"ID of On-Call Duty Policy associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyEscalationRuleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicyEscalationRule,
title: "On-Call Duty Policy Escalation Rule",
description:
"On-Call Duty Policy Escalation Rule associated with this email (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicyEscalationRule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyEscalationRuleId" })
public onCallDutyPolicyEscalationRule?: OnCallDutyPolicyEscalationRule =
undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Escalation Rule ID",
description:
"ID of On-Call Duty Policy Escalation Rule associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyEscalationRuleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyScheduleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicySchedule,
title: "On-Call Duty Policy Schedule",
description:
"On-Call Duty Policy Schedule associated with this email (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicySchedule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyScheduleId" })
public onCallDutyPolicySchedule?: OnCallDutyPolicySchedule = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Schedule ID",
description:
"ID of On-Call Duty Policy Schedule associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyScheduleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "teamId",
type: TableColumnType.Entity,
modelType: Team,
title: "Team",
description: "Team associated with this email (if any)",
})
@ManyToOne(
() => {
return Team;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "teamId" })
public team?: Team = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadEmailLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Team ID",
description: "ID of Team associated with this email (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public teamId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],

View File

@@ -48,6 +48,7 @@ export default class GlobalConfig extends GlobalConfigModel {
type: TableColumnType.Boolean,
title: "Disable Signup",
description: "Should we disable new user sign up to this server?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -338,6 +339,7 @@ export default class GlobalConfig extends GlobalConfigModel {
type: TableColumnType.Boolean,
title: "Is Master API Key Enabled",
description: "Is Master API Key Enabled?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -27,6 +27,7 @@ import IconProp from "../../Types/Icon/IconProp";
import { JSONObject } from "../../Types/JSON";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import {
Column,
Entity,
@@ -733,29 +734,74 @@ export default class Incident extends BaseModel {
public changeMonitorStatusToId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectIncident,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectIncident,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectIncident,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this incident?",
defaultValue: false,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description:
"Status of notification sent to subscribers about this incident",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotifiedOnIncidentCreated?: boolean = undefined;
public subscriberNotificationStatusOnIncidentCreated?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectIncident,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectIncident,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectIncident,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message",
description:
"Status message for subscriber notifications - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [

View File

@@ -17,6 +17,7 @@ import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@@ -341,29 +342,73 @@ export default class IncidentPublicNote extends BaseModel {
public note?: string = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentPublicNote,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentPublicNote,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentPublicNote,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this note?",
defaultValue: false,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description: "Status of notification sent to subscribers about this note",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotifiedOnNoteCreated?: boolean = undefined;
public subscriberNotificationStatusOnNoteCreated?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentPublicNote,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentPublicNote,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentPublicNote,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message",
description:
"Status message for subscriber notifications - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [

View File

@@ -19,6 +19,7 @@ import IconProp from "../../Types/Icon/IconProp";
import { JSONObject } from "../../Types/JSON";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@@ -391,29 +392,74 @@ export default class IncidentStateTimeline extends BaseModel {
public incidentStateId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentStateTimeline,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentStateTimeline,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentStateTimeline,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this incident state change?",
defaultValue: false,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description:
"Status of notification sent to subscribers about this incident state change",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotified?: boolean = undefined;
public subscriberNotificationStatus?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentStateTimeline,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentStateTimeline,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentStateTimeline,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message",
description:
"Status message for subscriber notifications - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [
@@ -435,6 +481,7 @@ export default class IncidentStateTimeline extends BaseModel {
type: TableColumnType.Boolean,
title: "Should subscribers be notified?",
description: "Should subscribers be notified about this state change?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -461,6 +508,7 @@ export default class IncidentStateTimeline extends BaseModel {
isDefaultValueColumn: true,
title: "Are Owners Notified",
description: "Are owners notified of state change?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -716,6 +716,77 @@ export default class IncidentTemplate extends BaseModel {
})
public changeMonitorStatusToId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentTemplate,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentTemplate,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "initialIncidentStateId",
type: TableColumnType.Entity,
modelType: IncidentState,
title: "Initial Incident State",
description:
"Relation to Incident State Object. Incidents created from this template will start in this state.",
})
@ManyToOne(
() => {
return IncidentState;
},
{
eager: false,
nullable: true,
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "initialIncidentStateId" })
public initialIncidentState?: IncidentState = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentTemplate,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentTemplate,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentTemplate,
],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
title: "Initial Incident State ID",
description:
"Relation to Incident State Object ID. Incidents created from this template will start in this state.",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public initialIncidentStateId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,

View File

@@ -100,6 +100,8 @@ import ServiceCopilotCodeRepository from "./ServiceCopilotCodeRepository";
import ShortLink from "./ShortLink";
// SMS
import SmsLog from "./SmsLog";
import PushNotificationLog from "./PushNotificationLog";
import WorkspaceNotificationLog from "./WorkspaceNotificationLog";
// Status Page
import StatusPage from "./StatusPage";
import StatusPageAnnouncement from "./StatusPageAnnouncement";
@@ -114,6 +116,7 @@ import StatusPageOwnerTeam from "./StatusPageOwnerTeam";
import StatusPageOwnerUser from "./StatusPageOwnerUser";
import StatusPagePrivateUser from "./StatusPagePrivateUser";
import StatusPageResource from "./StatusPageResource";
import StatusPageSCIM from "./StatusPageSCIM";
import StatusPageSSO from "./StatusPageSso";
import StatusPageSubscriber from "./StatusPageSubscriber";
// Team
@@ -175,10 +178,11 @@ import WorkspaceUserAuthToken from "./WorkspaceUserAuthToken";
import WorkspaceProjectAuthToken from "./WorkspaceProjectAuthToken";
import WorkspaceSetting from "./WorkspaceSetting";
import WorkspaceNotificationRule from "./WorkspaceNotificationRule";
import ProjectUser from "./ProjectUser";
import OnCallDutyPolicyUserOverride from "./OnCallDutyPolicyUserOverride";
import MonitorFeed from "./MonitorFeed";
import MetricType from "./MetricType";
import ProjectSCIM from "./ProjectSCIM";
const AllModelTypes: Array<{
new (): BaseModel;
@@ -276,6 +280,7 @@ const AllModelTypes: Array<{
ProjectSSO,
StatusPageSSO,
StatusPageSCIM,
MonitorProbe,
@@ -289,6 +294,8 @@ const AllModelTypes: Array<{
StatusPageOwnerUser,
SmsLog,
PushNotificationLog,
WorkspaceNotificationLog,
CallLog,
EmailLog,
@@ -373,13 +380,13 @@ const AllModelTypes: Array<{
WorkspaceSetting,
WorkspaceNotificationRule,
ProjectUser,
MonitorFeed,
MetricType,
OnCallDutyPolicyTimeLog,
ProjectSCIM,
];
const modelTypeMap: { [key: string]: { new (): BaseModel } } = {};

View File

@@ -456,6 +456,7 @@ export default class MonitorStatus extends BaseModel {
canReadOnRelationQuery: true,
title: "Is Offline State",
description: "Is this monitor in offline state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -455,7 +455,7 @@ export default class OnCallDutyPolicy extends BaseModel {
@TableColumn({
required: true,
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
type: TableColumnType.Number,
canReadOnRelationQuery: true,
title: "Repeat Policy Times If No One Acknowledges",
description:

View File

@@ -46,7 +46,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
Permission.EditProjectOnCallDutyPolicyEscalationRule,
],
})
@CrudApiEndpoint(new Route("/on-call-duty-policy-esclation-rule"))
@CrudApiEndpoint(new Route("/on-call-duty-policy-escalation-rule"))
@Entity({
name: "OnCallDutyPolicyEscalationRule",
})

View File

@@ -47,7 +47,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
Permission.EditProjectOnCallDutyPolicyEscalationRuleSchedule,
],
})
@CrudApiEndpoint(new Route("/on-call-duty-policy-esclation-rule-schedule"))
@CrudApiEndpoint(new Route("/on-call-duty-policy-escalation-rule-schedule"))
@Entity({
name: "OnCallDutyPolicyEscalationRuleSchedule",
})

View File

@@ -47,7 +47,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
Permission.EditProjectOnCallDutyPolicyEscalationRuleTeam,
],
})
@CrudApiEndpoint(new Route("/on-call-duty-policy-esclation-rule-team"))
@CrudApiEndpoint(new Route("/on-call-duty-policy-escalation-rule-team"))
@Entity({
name: "OnCallDutyPolicyEscalationRuleTeam",
})

View File

@@ -46,7 +46,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
Permission.EditProjectOnCallDutyPolicyEscalationRuleUser,
],
})
@CrudApiEndpoint(new Route("/on-call-duty-policy-esclation-rule-user"))
@CrudApiEndpoint(new Route("/on-call-duty-policy-escalation-rule-user"))
@Entity({
name: "OnCallDutyPolicyEscalationRuleUser",
})

View File

@@ -248,6 +248,84 @@ export default class Project extends TenantModel {
})
public paymentProviderCustomerId?: string = undefined;
@ColumnAccessControl({
create: [Permission.ProjectOwner, Permission.ManageProjectBilling],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProject,
Permission.UnAuthorizedSsoUser,
Permission.ProjectUser,
],
update: [Permission.ProjectOwner, Permission.ManageProjectBilling],
})
@TableColumn({
type: TableColumnType.LongText,
title: "Business Details / Billing Address",
description:
"Business legal name, address and any tax information to appear on invoices.",
})
@Column({
type: ColumnType.LongText,
length: ColumnLength.LongText,
nullable: true,
unique: false,
})
public businessDetails?: string = undefined;
@ColumnAccessControl({
create: [Permission.ProjectOwner, Permission.ManageProjectBilling],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProject,
Permission.UnAuthorizedSsoUser,
Permission.ProjectUser,
],
update: [Permission.ProjectOwner, Permission.ManageProjectBilling],
})
@TableColumn({
type: TableColumnType.ShortText,
title: "Business Country (ISO Alpha-2)",
description:
"Two-letter ISO country code for billing address (e.g., US, GB, DE).",
})
@Column({
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
nullable: true,
unique: false,
})
public businessDetailsCountry?: string = undefined;
@ColumnAccessControl({
create: [Permission.ProjectOwner, Permission.ManageProjectBilling],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProject,
Permission.UnAuthorizedSsoUser,
Permission.ProjectUser,
],
update: [Permission.ProjectOwner, Permission.ManageProjectBilling],
})
@TableColumn({
type: TableColumnType.Email,
title: "Finance / Accounting Email",
description:
"Invoices, receipts and billing related notifications will be sent to this email in addition to project owner.",
})
@Column({
type: ColumnType.Email,
length: ColumnLength.Email,
nullable: true,
unique: false,
})
public financeAccountingEmail?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
@@ -1213,4 +1291,37 @@ export default class Project extends TenantModel {
type: ColumnType.Boolean,
})
public letCustomerSupportAccessProject?: boolean = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProject,
Permission.UnAuthorizedSsoUser,
Permission.ProjectUser,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProject,
],
})
@TableColumn({
required: false,
type: TableColumnType.Boolean,
isDefaultValueColumn: false,
title: "Do NOT auto-add Global Probes to new monitors",
description:
"If enabled, global probes will NOT be automatically added to new monitors. Enable this only if you are using ONLY custom probes to monitor your resources.",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
nullable: false,
unique: false,
default: false,
})
public doNotAddGlobalProbesByDefaultOnNewMonitors?: boolean = undefined;
}

View File

@@ -0,0 +1,451 @@
import Project from "./Project";
import Team from "./Team";
import User from "./User";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import { PlanType } from "../../Types/Billing/SubscriptionPlan";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
import TableBillingAccessControl from "../../Types/Database/AccessControl/TableBillingAccessControl";
import ColumnLength from "../../Types/Database/ColumnLength";
import ColumnType from "../../Types/Database/ColumnType";
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
import TableColumn from "../../Types/Database/TableColumn";
import TableColumnType from "../../Types/Database/TableColumnType";
import TableMetadata from "../../Types/Database/TableMetadata";
import TenantColumn from "../../Types/Database/TenantColumn";
import UniqueColumnBy from "../../Types/Database/UniqueColumnBy";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import {
Column,
Entity,
Index,
JoinColumn,
JoinTable,
ManyToMany,
ManyToOne,
} from "typeorm";
@TableBillingAccessControl({
create: PlanType.Scale,
read: PlanType.Scale,
update: PlanType.Scale,
delete: PlanType.Scale,
})
@TenantColumn("projectId")
@TableAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
delete: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.DeleteProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@CrudApiEndpoint(new Route("/project-scim"))
@TableMetadata({
tableName: "ProjectSCIM",
singularName: "SCIM",
pluralName: "SCIM",
icon: IconProp.Lock,
tableDescription: "Manage SCIM auto-provisioning for your project",
})
@Entity({
name: "ProjectSCIM",
})
export default class ProjectSCIM extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "projectId",
type: TableColumnType.Entity,
modelType: Project,
title: "Project",
description: "Relation to Project Resource in which this object belongs",
})
@ManyToOne(
() => {
return Project;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "projectId" })
public project?: Project = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
canReadOnRelationQuery: true,
title: "Project ID",
description: "ID of your OneUptime Project in which this object belongs",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public projectId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
canReadOnRelationQuery: true,
title: "Name",
description: "Any friendly name for this SCIM configuration",
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
@UniqueColumnBy("projectId")
public name?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@TableColumn({
required: false,
type: TableColumnType.LongText,
title: "Description",
description: "Friendly description to help you remember",
})
@Column({
nullable: true,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public description?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.LongText,
title: "Bearer Token",
description: "Bearer token for SCIM authentication. Keep this secure.",
})
@Column({
nullable: false,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public bearerToken?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@TableColumn({
required: false,
type: TableColumnType.EntityArray,
modelType: Team,
title: "Default Teams",
description: "Default teams that new users will be added to via SCIM",
})
@ManyToMany(
() => {
return Team;
},
{ eager: false },
)
@JoinTable({
name: "ProjectScimTeam",
inverseJoinColumn: {
name: "teamId",
referencedColumnName: "_id",
},
joinColumn: {
name: "projectScimId",
referencedColumnName: "_id",
},
})
public teams?: Array<Team> = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
title: "Auto Provision Users",
description: "Automatically create users when they are added via SCIM",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
default: true,
})
public autoProvisionUsers?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditProjectSSO,
],
})
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
title: "Auto Deprovision Users",
description: "Automatically remove users when they are removed via SCIM",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
default: true,
})
public autoDeprovisionUsers?: boolean = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "createdByUserId",
type: TableColumnType.Entity,
modelType: User,
title: "Created by User",
description:
"Relation to User who created this object (if this object was created by a User)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "createdByUserId" })
public createdByUser?: User = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateProjectSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Created by User ID",
description:
"User ID who created this object (if this object was created by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public createdByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "deletedByUserId",
type: TableColumnType.Entity,
modelType: User,
title: "Deleted by User",
description:
"Relation to User who deleted this object (if this object was deleted by a User)",
})
@ManyToOne(
() => {
return User;
},
{
cascade: false,
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "deletedByUserId" })
public deletedByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectSSO,
],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Deleted by User ID",
description:
"User ID who deleted this object (if this object was deleted by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public deletedByUserId?: ObjectID = undefined;
}

View File

@@ -578,7 +578,11 @@ export default class ProjectSSO extends BaseModel {
],
update: [],
})
@TableColumn({ isDefaultValueColumn: true, type: TableColumnType.Boolean })
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
default: false,

View File

@@ -1,336 +0,0 @@
import Project from "./Project";
import Team from "./Team";
import User from "./User";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
import AllowUserQueryWithoutTenant from "../../Types/Database/AllowUserQueryWithoutTenant";
import ColumnType from "../../Types/Database/ColumnType";
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
import CurrentUserCanAccessRecordBy from "../../Types/Database/CurrentUserCanAccessRecordBy";
import MultiTenentQueryAllowed from "../../Types/Database/MultiTenentQueryAllowed";
import TableColumn from "../../Types/Database/TableColumn";
import TableColumnType from "../../Types/Database/TableColumnType";
import TableMetadata from "../../Types/Database/TableMetadata";
import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import {
Column,
Entity,
Index,
JoinColumn,
JoinTable,
ManyToMany,
ManyToOne,
} from "typeorm";
@TableAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectTeam,
Permission.CurrentUser,
],
delete: [],
update: [],
})
@MultiTenentQueryAllowed(true)
@AllowUserQueryWithoutTenant(true)
@CurrentUserCanAccessRecordBy("userId")
@TenantColumn("projectId")
@CrudApiEndpoint(new Route("/project-user"))
@Entity({
name: "ProjectUser",
})
@TableMetadata({
tableName: "ProjectUser",
singularName: "User",
pluralName: "Users",
icon: IconProp.User,
tableDescription:
"This model connects users and teams. This is an internal table. Its a view on TeamMembers table.",
})
export default class ProjectUser extends BaseModel {
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectTeam,
Permission.CurrentUser,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.EntityArray,
modelType: Team,
title: "Teams",
description: "Teams to which this user belongs.",
})
@ManyToMany(
() => {
return Team;
},
{ eager: false },
)
@JoinTable({
name: "ProjectUserAcceptedTeams",
inverseJoinColumn: {
name: "teamId",
referencedColumnName: "_id",
},
joinColumn: {
name: "projectUserId",
referencedColumnName: "_id",
},
})
public acceptedTeams?: Array<Team> = undefined; // user is accepted to these teams. This is a view on TeamMembers table.
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectTeam,
Permission.CurrentUser,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.EntityArray,
modelType: Team,
title: "Teams",
description: "Teams to which this user belongs.",
})
@ManyToMany(
() => {
return Team;
},
{ eager: false },
)
@JoinTable({
name: "ProjectUserInvitedTeams",
inverseJoinColumn: {
name: "teamId",
referencedColumnName: "_id",
},
joinColumn: {
name: "projectUserId",
referencedColumnName: "_id",
},
})
public invitedTeams?: Array<Team> = undefined; // user is invited to these teams.
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectTeam,
Permission.CurrentUser,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "projectId",
type: TableColumnType.Entity,
modelType: Project,
title: "Project",
description: "Relation to Project Resource in which this object belongs",
})
@ManyToOne(
() => {
return Project;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "projectId" })
public project?: Project = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectTeam,
Permission.CurrentUser,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
canReadOnRelationQuery: true,
title: "Project ID",
description: "ID of your OneUptime Project in which this object belongs",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public projectId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ReadProjectTeam,
Permission.ProjectMember,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "userId",
type: TableColumnType.Entity,
modelType: User,
title: "User",
description: "User who belongs to this team.",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: false,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "userId" })
public user?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectTeam,
Permission.CurrentUser,
],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
title: "User ID",
description: "ID of User who belongs to this team",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public userId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "createdByUserId",
type: TableColumnType.Entity,
modelType: User,
title: "Created by User",
description:
"Relation to User who created this object (if this object was created by a User)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "createdByUserId" })
public createdByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Created by User ID",
description:
"User ID who created this object (if this object was created by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public createdByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "deletedByUserId",
type: TableColumnType.Entity,
title: "Deleted by User",
modelType: User,
description:
"Relation to User who deleted this object (if this object was deleted by a User)",
})
@ManyToOne(
() => {
return User;
},
{
cascade: false,
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "deletedByUserId" })
public deletedByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Deleted by User ID",
description:
"User ID who deleted this object (if this object was deleted by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public deletedByUserId?: ObjectID = undefined;
}

View File

@@ -0,0 +1,877 @@
import Project from "./Project";
import Incident from "./Incident";
import Alert from "./Alert";
import ScheduledMaintenance from "./ScheduledMaintenance";
import StatusPage from "./StatusPage";
import StatusPageAnnouncement from "./StatusPageAnnouncement";
import User from "./User";
import OnCallDutyPolicy from "./OnCallDutyPolicy";
import OnCallDutyPolicyEscalationRule from "./OnCallDutyPolicyEscalationRule";
import OnCallDutyPolicySchedule from "./OnCallDutyPolicySchedule";
import Team from "./Team";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
import ColumnLength from "../../Types/Database/ColumnLength";
import ColumnType from "../../Types/Database/ColumnType";
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
import TableColumn from "../../Types/Database/TableColumn";
import TableColumnType from "../../Types/Database/TableColumnType";
import TableMetadata from "../../Types/Database/TableMetadata";
import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import PushStatus from "../../Types/PushNotification/PushStatus";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@TenantColumn("projectId")
@TableAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
delete: [],
update: [],
})
@CrudApiEndpoint(new Route("/push-notification-log"))
@Entity({
name: "PushNotificationLog",
})
@EnableWorkflow({
create: true,
delete: false,
update: false,
})
@TableMetadata({
tableName: "PushNotificationLog",
singularName: "Push Notification Log",
pluralName: "Push Notification Logs",
icon: IconProp.Bell,
tableDescription:
"Logs of all the Push Notifications sent out to all users and subscribers for this project.",
})
export default class PushNotificationLog extends BaseModel {
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "projectId",
type: TableColumnType.Entity,
modelType: Project,
title: "Project",
description: "Relation to Project Resource in which this object belongs",
})
@ManyToOne(
() => {
return Project;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "projectId" })
public project?: Project = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
canReadOnRelationQuery: true,
title: "Project ID",
description: "ID of your OneUptime Project in which this object belongs",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public projectId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
required: true,
type: TableColumnType.LongText,
title: "Title",
description: "Title of the push notification",
canReadOnRelationQuery: false,
})
@Column({
nullable: false,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public title?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.VeryLongText,
title: "Body",
description: "Body of the push notification",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.VeryLongText,
})
public body?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.ShortText,
title: "Device Type",
description: "Type of device this was sent to (e.g., web)",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public deviceType?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.ShortText,
title: "Device Name",
description: "Name of the device this was sent to",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public deviceName?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.LongText,
title: "Status Message",
description: "Status Message (if any)",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public statusMessage?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
title: "Status",
description: "Status of the push notification",
canReadOnRelationQuery: false,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public status?: PushStatus = undefined;
// Relations to resources that triggered this push notification (nullable)
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "incidentId",
type: TableColumnType.Entity,
modelType: Incident,
title: "Incident",
description: "Incident associated with this Push (if any)",
})
@ManyToOne(
() => {
return Incident;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "incidentId" })
public incident?: Incident = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Incident ID",
description: "ID of Incident associated with this Push (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public incidentId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "userId",
type: TableColumnType.Entity,
modelType: User,
title: "User",
description: "User who initiated this Push notification (if any)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "userId" })
public user?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "User ID",
description: "ID of User who initiated this Push notification (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public userId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "alertId",
type: TableColumnType.Entity,
modelType: Alert,
title: "Alert",
description: "Alert associated with this Push (if any)",
})
@ManyToOne(
() => {
return Alert;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "alertId" })
public alert?: Alert = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Alert ID",
description: "ID of Alert associated with this Push (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public alertId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "scheduledMaintenanceId",
type: TableColumnType.Entity,
modelType: ScheduledMaintenance,
title: "Scheduled Maintenance",
description: "Scheduled Maintenance associated with this Push (if any)",
})
@ManyToOne(
() => {
return ScheduledMaintenance;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "scheduledMaintenanceId" })
public scheduledMaintenance?: ScheduledMaintenance = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Scheduled Maintenance ID",
description:
"ID of Scheduled Maintenance associated with this Push (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public scheduledMaintenanceId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageId",
type: TableColumnType.Entity,
modelType: StatusPage,
title: "Status Page",
description: "Status Page associated with this Push (if any)",
})
@ManyToOne(
() => {
return StatusPage;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageId" })
public statusPage?: StatusPage = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page ID",
description: "ID of Status Page associated with this Push (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageAnnouncementId",
type: TableColumnType.Entity,
modelType: StatusPageAnnouncement,
title: "Status Page Announcement",
description: "Status Page Announcement associated with this Push (if any)",
})
@ManyToOne(
() => {
return StatusPageAnnouncement;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageAnnouncementId" })
public statusPageAnnouncement?: StatusPageAnnouncement = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page Announcement ID",
description:
"ID of Status Page Announcement associated with this Push (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageAnnouncementId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicy,
title: "On-Call Duty Policy",
description:
"On-Call Duty Policy associated with this Push Notification (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicy;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyId" })
public onCallDutyPolicy?: OnCallDutyPolicy = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy ID",
description:
"ID of On-Call Duty Policy associated with this Push Notification (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyEscalationRuleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicyEscalationRule,
title: "On-Call Duty Policy Escalation Rule",
description:
"On-Call Duty Policy Escalation Rule associated with this Push Notification (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicyEscalationRule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyEscalationRuleId" })
public onCallDutyPolicyEscalationRule?: OnCallDutyPolicyEscalationRule =
undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Escalation Rule ID",
description:
"ID of On-Call Duty Policy Escalation Rule associated with this Push Notification (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyEscalationRuleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyScheduleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicySchedule,
title: "On-Call Duty Policy Schedule",
description:
"On-Call Duty Policy Schedule associated with this Push Notification (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicySchedule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyScheduleId" })
public onCallDutyPolicySchedule?: OnCallDutyPolicySchedule = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Schedule ID",
description:
"ID of On-Call Duty Policy Schedule associated with this Push Notification (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyScheduleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "teamId",
type: TableColumnType.Entity,
modelType: Team,
title: "Team",
description: "Team associated with this Push Notification (if any)",
})
@ManyToOne(
() => {
return Team;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "teamId" })
public team?: Team = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Team ID",
description: "ID of Team associated with this Push Notification (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public teamId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "deletedByUserId",
type: TableColumnType.Entity,
title: "Deleted by User",
modelType: User,
description:
"Relation to User who deleted this object (if this object was deleted by a User)",
})
@ManyToOne(
() => {
return User;
},
{
cascade: false,
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "deletedByUserId" })
public deletedByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Deleted by User ID",
description:
"User ID who deleted this object (if this object was deleted by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public deletedByUserId?: ObjectID = undefined;
}

View File

@@ -269,6 +269,7 @@ export default class Reseller extends BaseModel {
canReadOnRelationQuery: true,
title: "Enable Telemetry Features",
description: "Should we enable telemetry features for this reseller?",
defaultValue: false,
})
@Column({
nullable: true,

View File

@@ -25,6 +25,7 @@ import IconProp from "../../Types/Icon/IconProp";
import { JSONObject } from "../../Types/JSON";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import {
Column,
Entity,
@@ -715,29 +716,74 @@ export default class ScheduledMaintenance extends BaseModel {
public endsAt?: Date = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectScheduledMaintenance,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectScheduledMaintenance,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectScheduledMaintenance,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
title: "Status Page Subscribers Notified On Event Scheduled",
description: "Status Page Subscribers Notified On Event Scheduled",
defaultValue: false,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status On Event Scheduled",
description:
"Status of notification sent to subscribers when event was scheduled",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotifiedOnEventScheduled?: boolean = undefined;
public subscriberNotificationStatusOnEventScheduled?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentPublicNote,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectScheduledMaintenance,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectScheduledMaintenance,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message On Event Scheduled",
description:
"Status message for subscriber notifications when event is scheduled - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [

View File

@@ -17,6 +17,7 @@ import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@@ -342,29 +343,73 @@ export default class ScheduledMaintenancePublicNote extends BaseModel {
public note?: string = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateScheduledMaintenancePublicNote,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadScheduledMaintenancePublicNote,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditScheduledMaintenancePublicNote,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this note?",
defaultValue: false,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description: "Status of notification sent to subscribers about this note",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotifiedOnNoteCreated?: boolean = undefined;
public subscriberNotificationStatusOnNoteCreated?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateScheduledMaintenancePublicNote,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadScheduledMaintenancePublicNote,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditScheduledMaintenancePublicNote,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message",
description:
"Status message for subscriber notifications - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [

View File

@@ -423,6 +423,7 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Scheduled State",
description: "Is this state a scheduled state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -456,6 +457,7 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Ongoing State",
description: "Is this state a ongoing state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -489,6 +491,7 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Ended State",
description: "Is this state a ended state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -522,6 +525,7 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Resolved State",
description: "Is this state a resolved state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -18,6 +18,7 @@ import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@@ -388,29 +389,74 @@ export default class ScheduledMaintenanceStateTimeline extends BaseModel {
public scheduledMaintenanceStateId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateScheduledMaintenanceStateTimeline,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadScheduledMaintenanceStateTimeline,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditScheduledMaintenanceStateTimeline,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this incident state change?",
defaultValue: false,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description:
"Status of notification sent to subscribers about this scheduled maintenance state change",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotified?: boolean = undefined;
public subscriberNotificationStatus?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateScheduledMaintenanceStateTimeline,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadScheduledMaintenanceStateTimeline,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditScheduledMaintenanceStateTimeline,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message",
description:
"Status message for subscriber notifications - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [

View File

@@ -1,5 +1,14 @@
import Project from "./Project";
import Incident from "./Incident";
import Alert from "./Alert";
import ScheduledMaintenance from "./ScheduledMaintenance";
import StatusPage from "./StatusPage";
import StatusPageAnnouncement from "./StatusPageAnnouncement";
import User from "./User";
import OnCallDutyPolicy from "./OnCallDutyPolicy";
import OnCallDutyPolicyEscalationRule from "./OnCallDutyPolicyEscalationRule";
import OnCallDutyPolicySchedule from "./OnCallDutyPolicySchedule";
import Team from "./Team";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
@@ -256,6 +265,575 @@ export default class SmsLog extends BaseModel {
})
public smsCostInUSDCents?: number = undefined;
// Relations to resources that triggered this SMS (nullable)
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "incidentId",
type: TableColumnType.Entity,
modelType: Incident,
title: "Incident",
description: "Incident associated with this SMS (if any)",
})
@ManyToOne(
() => {
return Incident;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "incidentId" })
public incident?: Incident = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Incident ID",
description: "ID of Incident associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public incidentId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "userId",
type: TableColumnType.Entity,
modelType: User,
title: "User",
description: "User who initiated this SMS (if any)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "userId" })
public user?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "User ID",
description: "ID of User who initiated this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public userId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "alertId",
type: TableColumnType.Entity,
modelType: Alert,
title: "Alert",
description: "Alert associated with this SMS (if any)",
})
@ManyToOne(
() => {
return Alert;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "alertId" })
public alert?: Alert = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Alert ID",
description: "ID of Alert associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public alertId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "scheduledMaintenanceId",
type: TableColumnType.Entity,
modelType: ScheduledMaintenance,
title: "Scheduled Maintenance",
description: "Scheduled Maintenance associated with this SMS (if any)",
})
@ManyToOne(
() => {
return ScheduledMaintenance;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "scheduledMaintenanceId" })
public scheduledMaintenance?: ScheduledMaintenance = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Scheduled Maintenance ID",
description:
"ID of Scheduled Maintenance associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public scheduledMaintenanceId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageId",
type: TableColumnType.Entity,
modelType: StatusPage,
title: "Status Page",
description: "Status Page associated with this SMS (if any)",
})
@ManyToOne(
() => {
return StatusPage;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageId" })
public statusPage?: StatusPage = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page ID",
description: "ID of Status Page associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageAnnouncementId",
type: TableColumnType.Entity,
modelType: StatusPageAnnouncement,
title: "Status Page Announcement",
description: "Status Page Announcement associated with this SMS (if any)",
})
@ManyToOne(
() => {
return StatusPageAnnouncement;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageAnnouncementId" })
public statusPageAnnouncement?: StatusPageAnnouncement = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page Announcement ID",
description:
"ID of Status Page Announcement associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageAnnouncementId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicy,
title: "On-Call Duty Policy",
description: "On-Call Duty Policy associated with this SMS (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicy;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyId" })
public onCallDutyPolicy?: OnCallDutyPolicy = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy ID",
description: "ID of On-Call Duty Policy associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyEscalationRuleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicyEscalationRule,
title: "On-Call Duty Policy Escalation Rule",
description:
"On-Call Duty Policy Escalation Rule associated with this SMS (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicyEscalationRule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyEscalationRuleId" })
public onCallDutyPolicyEscalationRule?: OnCallDutyPolicyEscalationRule =
undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Escalation Rule ID",
description:
"ID of On-Call Duty Policy Escalation Rule associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyEscalationRuleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyScheduleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicySchedule,
title: "On-Call Duty Policy Schedule",
description:
"On-Call Duty Policy Schedule associated with this SMS (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicySchedule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyScheduleId" })
public onCallDutyPolicySchedule?: OnCallDutyPolicySchedule = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Schedule ID",
description:
"ID of On-Call Duty Policy Schedule associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyScheduleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "teamId",
type: TableColumnType.Entity,
modelType: Team,
title: "Team",
description: "Team associated with this SMS (if any)",
})
@ManyToOne(
() => {
return Team;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "teamId" })
public team?: Team = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadSmsLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Team ID",
description: "ID of Team associated with this SMS (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public teamId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],

View File

@@ -1179,6 +1179,45 @@ export default class StatusPage extends BaseModel {
})
public enableSlackSubscribers?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectStatusPage,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectStatusPage,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectStatusPage,
],
})
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
title: "Enable Microsoft Teams Subscribers",
description:
"Can Microsoft Teams subscribers subscribe to this Status Page?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
default: false,
})
@ColumnBillingAccessControl({
read: PlanType.Free,
update: PlanType.Scale,
create: PlanType.Free,
})
public enableMicrosoftTeamsSubscribers?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
@@ -1438,7 +1477,12 @@ export default class StatusPage extends BaseModel {
public callSmsConfigId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectStatusPage,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -1490,6 +1534,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Number,
required: true,
isDefaultValueColumn: true,
defaultValue: 14,
title: "Show incident history in days",
description:
"How many days of incident history should be shown on the status page (in days)?",
@@ -1526,6 +1571,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Number,
required: true,
isDefaultValueColumn: true,
defaultValue: 14,
title: "Show announcement history in days",
description:
"How many days of announcement history should be shown on the status page (in days)?",
@@ -1562,6 +1608,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Number,
required: true,
isDefaultValueColumn: true,
defaultValue: 14,
title: "Show scheduled event history in days",
description:
"How many days of scheduled event history should be shown on the status page (in days)?",
@@ -1633,6 +1680,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Hide Powered By OneUptime Branding",
description: "Hide Powered By OneUptime Branding?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -1706,6 +1754,7 @@ export default class StatusPage extends BaseModel {
required: false,
type: TableColumnType.EntityArray,
modelType: MonitorStatus,
isDefaultValueColumn: true,
title: "Downtime Monitor Statuses",
description:
'List of monitors statuses that are considered as "down" for this status page.',
@@ -1788,6 +1837,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Is Report Enabled",
description: "Is Report Enabled for this Status Page?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -1931,6 +1981,7 @@ export default class StatusPage extends BaseModel {
})
@TableColumn({
type: TableColumnType.Number,
defaultValue: 30,
title: "Report data for the last N days",
description: "How many days of data should be included in the report?",
})
@@ -1971,6 +2022,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Show Overall Uptime Percent on Status Page",
description: "Show Overall Uptime Percent on Status Page?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -2007,6 +2059,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.ShortText,
title: "Overall Uptime Percent Precision",
required: false,
defaultValue: UptimePrecision.TWO_DECIMAL,
description: "Overall Precision of uptime percent for this status page.",
})
@Column({
@@ -2109,6 +2162,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Show Incidents on Status Page",
description: "Show Incidents on Status Page?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -2147,6 +2201,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Show Announcements on Status Page",
description: "Show Announcements on Status Page?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -2185,6 +2240,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Show Scheduled Maintenance Events on Status Page",
description: "Show Scheduled Maintenance Events on Status Page?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -2223,6 +2279,7 @@ export default class StatusPage extends BaseModel {
type: TableColumnType.Boolean,
title: "Show Subscriber Page on Status Page",
description: "Show Subscriber Page on Status Page?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -1,3 +1,4 @@
import Monitor from "./Monitor";
import Project from "./Project";
import StatusPage from "./StatusPage";
import User from "./User";
@@ -21,6 +22,7 @@ import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
import {
Column,
Entity,
@@ -197,6 +199,53 @@ export default class StatusPageAnnouncement extends BaseModel {
})
public statusPages?: Array<StatusPage> = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncement,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageAnnouncement,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditStatusPageAnnouncement,
],
})
@TableColumn({
required: false,
type: TableColumnType.EntityArray,
modelType: Monitor,
title: "Monitors",
description:
"List of monitors affected by this announcement. If none are selected, all subscribers will be notified.",
})
@ManyToMany(
() => {
return Monitor;
},
{ eager: false },
)
@JoinTable({
name: "AnnouncementMonitor",
inverseJoinColumn: {
name: "monitorId",
referencedColumnName: "_id",
},
joinColumn: {
name: "announcementId",
referencedColumnName: "_id",
},
})
public monitors?: Array<Monitor> = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
@@ -443,27 +492,71 @@ export default class StatusPageAnnouncement extends BaseModel {
public deletedByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncement,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageAnnouncement,
],
update: [],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditStatusPageAnnouncement,
],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.Boolean,
defaultValue: false,
type: TableColumnType.ShortText,
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
})
@Column({
type: ColumnType.Boolean,
default: false,
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
})
public isStatusPageSubscribersNotified?: boolean = undefined;
public subscriberNotificationStatus?: StatusPageSubscriberNotificationStatus =
undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncement,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageAnnouncement,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditStatusPageAnnouncement,
],
})
@TableColumn({
type: TableColumnType.VeryLongText,
title: "Notification Status Message",
description:
"Status message for subscriber notifications - includes success messages, failure reasons, or skip reasons",
required: false,
})
@Column({
type: ColumnType.VeryLongText,
nullable: true,
})
public subscriberNotificationStatusMessage?: string = undefined;
@ColumnAccessControl({
create: [
@@ -485,6 +578,7 @@ export default class StatusPageAnnouncement extends BaseModel {
type: TableColumnType.Boolean,
title: "Should subscribers be notified?",
description: "Should subscribers be notified about this announcement?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -493,7 +587,12 @@ export default class StatusPageAnnouncement extends BaseModel {
public shouldStatusPageSubscribersBeNotified?: boolean = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncement,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -511,6 +610,7 @@ export default class StatusPageAnnouncement extends BaseModel {
isDefaultValueColumn: true,
title: "Are Owners Notified",
description: "Are owners notified of this announcement?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -1,3 +1,4 @@
import Monitor from "./Monitor";
import Project from "./Project";
import StatusPage from "./StatusPage";
import User from "./User";
@@ -328,6 +329,53 @@ export default class StatusPageAnnouncementTemplate extends BaseModel {
})
public statusPages?: Array<StatusPage> = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncementTemplate,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageAnnouncementTemplate,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditStatusPageAnnouncementTemplate,
],
})
@TableColumn({
required: false,
type: TableColumnType.EntityArray,
modelType: Monitor,
title: "Monitors",
description:
"List of monitors affected by this announcement template. If none are selected, all subscribers will be notified.",
})
@ManyToMany(
() => {
return Monitor;
},
{ eager: false },
)
@JoinTable({
name: "AnnouncementTemplateMonitor",
inverseJoinColumn: {
name: "monitorId",
referencedColumnName: "_id",
},
joinColumn: {
name: "announcementTemplateId",
referencedColumnName: "_id",
},
})
public monitors?: Array<Monitor> = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,

View File

@@ -474,7 +474,12 @@ export default class StatusPageDomain extends BaseModel {
public isCnameVerified?: boolean = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageDomain,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -489,6 +494,7 @@ export default class StatusPageDomain extends BaseModel {
type: TableColumnType.Boolean,
title: "SSL Ordered",
description: "Is SSL ordered?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -499,7 +505,12 @@ export default class StatusPageDomain extends BaseModel {
public isSslOrdered?: boolean = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageDomain,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -514,6 +525,7 @@ export default class StatusPageDomain extends BaseModel {
type: TableColumnType.Boolean,
title: "SSL Provisioned",
description: "Is SSL provisioned?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -0,0 +1,469 @@
import Project from "./Project";
import StatusPage from "./StatusPage";
import User from "./User";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import { PlanType } from "../../Types/Billing/SubscriptionPlan";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
import TableBillingAccessControl from "../../Types/Database/AccessControl/TableBillingAccessControl";
import CanAccessIfCanReadOn from "../../Types/Database/CanAccessIfCanReadOn";
import ColumnLength from "../../Types/Database/ColumnLength";
import ColumnType from "../../Types/Database/ColumnType";
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
import TableColumn from "../../Types/Database/TableColumn";
import TableColumnType from "../../Types/Database/TableColumnType";
import TableMetadata from "../../Types/Database/TableMetadata";
import TenantColumn from "../../Types/Database/TenantColumn";
import UniqueColumnBy from "../../Types/Database/UniqueColumnBy";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@TableBillingAccessControl({
create: PlanType.Scale,
read: PlanType.Scale,
update: PlanType.Scale,
delete: PlanType.Scale,
})
@CanAccessIfCanReadOn("statusPage")
@TenantColumn("projectId")
@TableAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
delete: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.DeleteStatusPageSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditStatusPageSSO,
],
})
@CrudApiEndpoint(new Route("/status-page-scim"))
@TableMetadata({
tableName: "StatusPageSCIM",
singularName: "Status Page SCIM",
pluralName: "Status Page SCIM",
icon: IconProp.Lock,
tableDescription: "Manage SCIM auto-provisioning for your status page",
})
@Entity({
name: "StatusPageSCIM",
})
export default class StatusPageSCIM extends BaseModel {
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "projectId",
type: TableColumnType.Entity,
modelType: Project,
title: "Project",
description: "Relation to Project Resource in which this object belongs",
})
@ManyToOne(
() => {
return Project;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "projectId" })
public project?: Project = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
canReadOnRelationQuery: true,
title: "Project ID",
description: "ID of your OneUptime Project in which this object belongs",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public projectId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageId",
type: TableColumnType.Entity,
modelType: StatusPage,
title: "Status Page",
description:
"Relation to Status Page Resource in which this object belongs",
})
@ManyToOne(
() => {
return StatusPage;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageId" })
public statusPage?: StatusPage = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
title: "Status Page ID",
description: "ID of your Status Page resource where this object belongs",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditStatusPageSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
canReadOnRelationQuery: true,
title: "Name",
description: "Any friendly name for this SCIM configuration",
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
@UniqueColumnBy("statusPageId")
public name?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditStatusPageSSO,
],
})
@TableColumn({
required: false,
type: TableColumnType.LongText,
title: "Description",
description: "Friendly description to help you remember",
})
@Column({
nullable: true,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public description?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ReadStatusPageSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditStatusPageSSO,
],
})
@TableColumn({
required: true,
type: TableColumnType.LongText,
title: "Bearer Token",
description: "Bearer token for SCIM authentication. Keep this secure.",
})
@Column({
nullable: false,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public bearerToken?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditStatusPageSSO,
],
})
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
title: "Auto Provision Users",
description:
"Automatically create status page users when they are added via SCIM",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
default: true,
})
public autoProvisionUsers?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.EditStatusPageSSO,
],
})
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
title: "Auto Deprovision Users",
description:
"Automatically remove status page users when they are removed via SCIM",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
default: true,
})
public autoDeprovisionUsers?: boolean = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "createdByUserId",
type: TableColumnType.Entity,
modelType: User,
title: "Created by User",
description:
"Relation to User who created this object (if this object was created by a User)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "createdByUserId" })
public createdByUser?: User = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.CreateStatusPageSSO,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Created by User ID",
description:
"User ID who created this object (if this object was created by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public createdByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "deletedByUserId",
type: TableColumnType.Entity,
modelType: User,
title: "Deleted by User",
description:
"Relation to User who deleted this object (if this object was deleted by a User)",
})
@ManyToOne(
() => {
return User;
},
{
cascade: false,
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "deletedByUserId" })
public deletedByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSSO,
],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Deleted by User ID",
description:
"User ID who deleted this object (if this object was deleted by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public deletedByUserId?: ObjectID = undefined;
}

View File

@@ -379,6 +379,65 @@ export default class StatusPageSubscriber extends BaseModel {
})
public slackWorkspaceName?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageSubscriber,
Permission.Public,
],
read: [],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.LongURL,
title: "Microsoft Teams Incoming Webhook URL",
description:
"Microsoft Teams incoming webhook URL to send notifications to Teams channel",
})
@Column({
nullable: true,
type: ColumnType.LongURL,
transformer: URL.getDatabaseTransformer(),
})
public microsoftTeamsIncomingWebhookUrl?: URL = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageSubscriber,
Permission.Public,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageSubscriber,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditStatusPageSubscriber,
],
})
@TableColumn({
required: false,
type: TableColumnType.VeryLongText,
title: "Microsoft Teams Workspace Name",
description:
"Name of the Microsoft Teams workspace for validation and identification",
})
@Column({
nullable: true,
type: ColumnType.VeryLongText,
})
public microsoftTeamsWorkspaceName?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
@@ -608,6 +667,7 @@ export default class StatusPageSubscriber extends BaseModel {
type: TableColumnType.Boolean,
title: "Send You Have Subscribed Message",
description: "Send You Have Subscribed Message when subscriber is created?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -642,6 +702,7 @@ export default class StatusPageSubscriber extends BaseModel {
title: "Is Subscribed to All Resources",
description:
"Is Subscriber Subscribed to All Resources on this status page?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,
@@ -676,6 +737,7 @@ export default class StatusPageSubscriber extends BaseModel {
title: "Is Subscribed to All Event Types",
description:
"Is Subscriber Subscribed to All Event Types (like Incidents, Scheduled Events, Announcements) on this status page?",
defaultValue: true,
})
@Column({
type: ColumnType.Boolean,

View File

@@ -442,6 +442,7 @@ export default class TableView extends BaseModel {
type: TableColumnType.Number,
canReadOnRelationQuery: true,
description: "Items on page",
defaultValue: 10,
})
@Column({
type: ColumnType.Number,

View File

@@ -146,7 +146,11 @@ export default class TelemetryUsageBilling extends BaseModel {
public productType?: ProductType = undefined;
@ColumnAccessControl({
create: [],
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ManageProjectBilling,
],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -158,6 +162,7 @@ export default class TelemetryUsageBilling extends BaseModel {
type: TableColumnType.Number,
title: "Retain Telemetry Data For Days",
description: "Number of days to retain telemetry data for this service.",
defaultValue: DEFAULT_RETENTION_IN_DAYS,
})
@Column({
type: ColumnType.Number,

View File

@@ -278,7 +278,11 @@ class UserNotificationSetting extends BaseModel {
read: [Permission.CurrentUser],
update: [Permission.CurrentUser],
})
@TableColumn({ isDefaultValueColumn: true, type: TableColumnType.Boolean })
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
default: false,

View File

@@ -0,0 +1,931 @@
import Project from "./Project";
import Incident from "./Incident";
import Alert from "./Alert";
import ScheduledMaintenance from "./ScheduledMaintenance";
import StatusPage from "./StatusPage";
import StatusPageAnnouncement from "./StatusPageAnnouncement";
import User from "./User";
import OnCallDutyPolicy from "./OnCallDutyPolicy";
import OnCallDutyPolicyEscalationRule from "./OnCallDutyPolicyEscalationRule";
import OnCallDutyPolicySchedule from "./OnCallDutyPolicySchedule";
import Team from "./Team";
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
import Route from "../../Types/API/Route";
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
import ColumnLength from "../../Types/Database/ColumnLength";
import ColumnType from "../../Types/Database/ColumnType";
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
import TableColumn from "../../Types/Database/TableColumn";
import TableColumnType from "../../Types/Database/TableColumnType";
import TableMetadata from "../../Types/Database/TableMetadata";
import TenantColumn from "../../Types/Database/TenantColumn";
import IconProp from "../../Types/Icon/IconProp";
import ObjectID from "../../Types/ObjectID";
import Permission from "../../Types/Permission";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
import WorkspaceNotificationStatus from "../../Types/Workspace/WorkspaceNotificationStatus";
import WorkspaceNotificationActionType from "../../Types/Workspace/WorkspaceNotificationActionType";
@EnableDocumentation()
@TenantColumn("projectId")
@TableAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
delete: [],
update: [],
})
@CrudApiEndpoint(new Route("/workspace-notification-log"))
@Entity({
name: "WorkspaceNotificationLog",
})
@EnableWorkflow({
create: true,
delete: false,
update: false,
})
@TableMetadata({
tableName: "WorkspaceNotificationLog",
singularName: "Workspace Notification Log",
pluralName: "Workspace Notification Logs",
icon: IconProp.Chat,
tableDescription:
"Logs of all workspace activities including messages, channel creation, user invitations, and button interactions for Slack and Microsoft Teams.",
})
export default class WorkspaceNotificationLog extends BaseModel {
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "projectId",
type: TableColumnType.Entity,
modelType: Project,
title: "Project",
description: "Relation to Project Resource in which this object belongs",
})
@ManyToOne(
() => {
return Project;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "projectId" })
public project?: Project = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: true,
canReadOnRelationQuery: true,
title: "Project ID",
description: "ID of your OneUptime Project in which this object belongs",
})
@Column({
type: ColumnType.ObjectID,
nullable: false,
transformer: ObjectID.getDatabaseTransformer(),
})
public projectId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
title: "Workspace Type",
description: "Type of Workspace - Slack, Microsoft Teams",
canReadOnRelationQuery: false,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public workspaceType?: WorkspaceType = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.ShortText,
title: "Channel ID",
description: "Channel ID where the message was sent",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public channelId?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.ShortText,
title: "Channel Name",
description: "Channel Name where the message was sent",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public channelName?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.ShortText,
title: "Thread ID",
description: "Thread ID of the message in the channel (if any)",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public threadId?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.VeryLongText,
title: "Message",
description: "Content of the message",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.VeryLongText,
})
public message?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: false,
type: TableColumnType.LongText,
title: "Status Message",
description: "Status Message (if any)",
canReadOnRelationQuery: false,
})
@Column({
nullable: true,
type: ColumnType.LongText,
length: ColumnLength.LongText,
})
public statusMessage?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
title: "Status",
description: "Status of the message",
canReadOnRelationQuery: false,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public status?: WorkspaceNotificationStatus = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
required: true,
type: TableColumnType.ShortText,
title: "Action Type",
description: "Type of workspace action performed",
canReadOnRelationQuery: false,
isDefaultValueColumn: true,
defaultValue: WorkspaceNotificationActionType.SendMessage,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
default: WorkspaceNotificationActionType.SendMessage,
})
public actionType?: WorkspaceNotificationActionType = undefined;
// Relations to resources that triggered this message (nullable)
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "incidentId",
type: TableColumnType.Entity,
modelType: Incident,
title: "Incident",
description: "Incident associated with this message (if any)",
})
@ManyToOne(
() => {
return Incident;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "incidentId" })
public incident?: Incident = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Incident ID",
description: "ID of Incident associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public incidentId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "userId",
type: TableColumnType.Entity,
modelType: User,
title: "User",
description: "User who initiated this workspace notification (if any)",
})
@ManyToOne(
() => {
return User;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "userId" })
public user?: User = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "User ID",
description:
"ID of User who initiated this workspace notification (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public userId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "alertId",
type: TableColumnType.Entity,
modelType: Alert,
title: "Alert",
description: "Alert associated with this message (if any)",
})
@ManyToOne(
() => {
return Alert;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "alertId" })
public alert?: Alert = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Alert ID",
description: "ID of Alert associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public alertId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "scheduledMaintenanceId",
type: TableColumnType.Entity,
modelType: ScheduledMaintenance,
title: "Scheduled Maintenance",
description: "Scheduled Maintenance associated with this message (if any)",
})
@ManyToOne(
() => {
return ScheduledMaintenance;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "scheduledMaintenanceId" })
public scheduledMaintenance?: ScheduledMaintenance = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Scheduled Maintenance ID",
description:
"ID of Scheduled Maintenance associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public scheduledMaintenanceId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageId",
type: TableColumnType.Entity,
modelType: StatusPage,
title: "Status Page",
description: "Status Page associated with this message (if any)",
})
@ManyToOne(
() => {
return StatusPage;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageId" })
public statusPage?: StatusPage = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page ID",
description: "ID of Status Page associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "statusPageAnnouncementId",
type: TableColumnType.Entity,
modelType: StatusPageAnnouncement,
title: "Status Page Announcement",
description:
"Status Page Announcement associated with this message (if any)",
})
@ManyToOne(
() => {
return StatusPageAnnouncement;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "statusPageAnnouncementId" })
public statusPageAnnouncement?: StatusPageAnnouncement = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadPushLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Status Page Announcement ID",
description:
"ID of Status Page Announcement associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public statusPageAnnouncementId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicy,
title: "On-Call Duty Policy",
description: "On-Call Duty Policy associated with this message (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicy;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyId" })
public onCallDutyPolicy?: OnCallDutyPolicy = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy ID",
description:
"ID of On-Call Duty Policy associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyEscalationRuleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicyEscalationRule,
title: "On-Call Duty Policy Escalation Rule",
description:
"On-Call Duty Policy Escalation Rule associated with this message (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicyEscalationRule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyEscalationRuleId" })
public onCallDutyPolicyEscalationRule?: OnCallDutyPolicyEscalationRule =
undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Escalation Rule ID",
description:
"ID of On-Call Duty Policy Escalation Rule associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyEscalationRuleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "onCallDutyPolicyScheduleId",
type: TableColumnType.Entity,
modelType: OnCallDutyPolicySchedule,
title: "On-Call Duty Policy Schedule",
description:
"On-Call Duty Policy Schedule associated with this message (if any)",
})
@ManyToOne(
() => {
return OnCallDutyPolicySchedule;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "onCallDutyPolicyScheduleId" })
public onCallDutyPolicySchedule?: OnCallDutyPolicySchedule = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "On-Call Duty Policy Schedule ID",
description:
"ID of On-Call Duty Policy Schedule associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public onCallDutyPolicyScheduleId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "teamId",
type: TableColumnType.Entity,
modelType: Team,
title: "Team",
description: "Team associated with this message (if any)",
})
@ManyToOne(
() => {
return Team;
},
{
eager: false,
nullable: true,
onDelete: "CASCADE",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "teamId" })
public team?: Team = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadWorkspaceNotificationLog,
],
update: [],
})
@Index()
@TableColumn({
type: TableColumnType.ObjectID,
required: false,
canReadOnRelationQuery: true,
title: "Team ID",
description: "ID of Team associated with this message (if any)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public teamId?: ObjectID = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
manyToOneRelationColumn: "deletedByUserId",
type: TableColumnType.Entity,
title: "Deleted by User",
modelType: User,
description:
"Relation to User who deleted this object (if this object was deleted by a User)",
})
@ManyToOne(
() => {
return User;
},
{
cascade: false,
eager: false,
nullable: true,
onDelete: "SET NULL",
orphanedRowAction: "nullify",
},
)
@JoinColumn({ name: "deletedByUserId" })
public deletedByUser?: User = undefined;
@ColumnAccessControl({
create: [],
read: [],
update: [],
})
@TableColumn({
type: TableColumnType.ObjectID,
title: "Deleted by User ID",
description:
"User ID who deleted this object (if this object was deleted by a User)",
})
@Column({
type: ColumnType.ObjectID,
nullable: true,
transformer: ObjectID.getDatabaseTransformer(),
})
public deletedByUserId?: ObjectID = undefined;
}

View File

@@ -18,13 +18,20 @@ import WorkspaceType from "../../Types/Workspace/WorkspaceType";
import Permission from "../../Types/Permission";
export interface MiscData {
[key: string]: string;
[key: string]: any;
}
export interface SlackMiscData extends MiscData {
teamId: string;
teamName: string;
botUserId: string;
channelCache?: {
[channelName: string]: {
id: string;
name: string;
lastUpdated: string;
};
};
}
@TenantColumn("projectId")

View File

@@ -235,13 +235,25 @@ export default class BaseAPI<
): Promise<void> {
await this.onBeforeList(req, res);
const skip: PositiveNumber = req.query["skip"]
? new PositiveNumber(req.query["skip"] as string)
: new PositiveNumber(0);
// Extract pagination parameters from query or body (for POST requests)
// Support both 'skip' and 'offset' parameters (offset is alias for skip)
let skipValue: number = 0;
let limitValue: number = DEFAULT_LIMIT;
const limit: PositiveNumber = req.query["limit"]
? new PositiveNumber(req.query["limit"] as string)
: new PositiveNumber(DEFAULT_LIMIT);
if (req.query["skip"]) {
skipValue = parseInt(req.query["skip"] as string, 10) || 0;
} else if (req.body && req.body["skip"] !== undefined) {
skipValue = parseInt(req.body["skip"] as string, 10) || 0;
}
if (req.query["limit"]) {
limitValue = parseInt(req.query["limit"] as string, 10) || DEFAULT_LIMIT;
} else if (req.body && req.body["limit"] !== undefined) {
limitValue = parseInt(req.body["limit"] as string, 10) || DEFAULT_LIMIT;
}
const skip: PositiveNumber = new PositiveNumber(skipValue);
const limit: PositiveNumber = new PositiveNumber(limitValue);
if (limit.toNumber() > LIMIT_PER_PROJECT) {
throw new BadRequestException(

View File

@@ -502,6 +502,7 @@ export default class StatusPageAPI extends BaseAPI<
footerHTML: true,
enableEmailSubscribers: true,
enableSlackSubscribers: true,
enableMicrosoftTeamsSubscribers: true,
enableSmsSubscribers: true,
isPublicStatusPage: true,
allowSubscribersToChooseResources: true,
@@ -2075,6 +2076,10 @@ export default class StatusPageAPI extends BaseAPI<
_id: true,
showAnnouncementAt: true,
endAnnouncementAt: true,
monitors: {
_id: true,
name: true,
},
},
skip: 0,
limit: LIMIT_PER_PROJECT,
@@ -2095,6 +2100,7 @@ export default class StatusPageAPI extends BaseAPI<
displayTooltip: true,
displayDescription: true,
displayName: true,
monitorGroupId: true,
monitor: {
_id: true,
currentMonitorStatusId: true,
@@ -2108,6 +2114,65 @@ export default class StatusPageAPI extends BaseAPI<
},
});
const monitorGroupIds: Array<ObjectID> = statusPageResources
.map((resource: StatusPageResource) => {
return resource.monitorGroupId!;
})
.filter((id: ObjectID) => {
return Boolean(id); // remove nulls
});
// get monitors in the group.
const monitorsInGroup: Dictionary<Array<ObjectID>> = {};
// get monitor status charts.
const monitorsOnStatusPage: Array<ObjectID> = statusPageResources
.map((monitor: StatusPageResource) => {
return monitor.monitorId!;
})
.filter((id: ObjectID) => {
return Boolean(id); // remove nulls
});
for (const monitorGroupId of monitorGroupIds) {
// get monitors in the group.
const groupResources: Array<MonitorGroupResource> =
await MonitorGroupResourceService.findBy({
query: {
monitorGroupId: monitorGroupId,
},
select: {
monitorId: true,
},
props: {
isRoot: true,
},
limit: LIMIT_PER_PROJECT,
skip: 0,
});
const monitorsInGroupIds: Array<ObjectID> = groupResources
.map((resource: MonitorGroupResource) => {
return resource.monitorId!;
})
.filter((id: ObjectID) => {
return Boolean(id); // remove nulls
});
for (const monitorId of monitorsInGroupIds) {
if (
!monitorsOnStatusPage.find((item: ObjectID) => {
return item.toString() === monitorId.toString();
})
) {
monitorsOnStatusPage.push(monitorId);
}
}
monitorsInGroup[monitorGroupId.toString()] = monitorsInGroupIds;
}
const response: JSONObject = {
announcements: BaseModel.toJSONArray(
announcements,
@@ -2117,6 +2182,7 @@ export default class StatusPageAPI extends BaseAPI<
statusPageResources,
StatusPageResource,
),
monitorsInGroup: JSONFunctions.serialize(monitorsInGroup),
};
return response;
@@ -2146,6 +2212,7 @@ export default class StatusPageAPI extends BaseAPI<
projectId: true,
enableEmailSubscribers: true,
enableSlackSubscribers: true,
enableMicrosoftTeamsSubscribers: true,
enableSmsSubscribers: true,
allowSubscribersToChooseResources: true,
allowSubscribersToChooseEventTypes: true,
@@ -2357,6 +2424,7 @@ export default class StatusPageAPI extends BaseAPI<
statusPage.smtpConfig,
),
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
);
}
@@ -2372,6 +2440,7 @@ export default class StatusPageAPI extends BaseAPI<
customTwilioConfig: ProjectCallSMSConfigService.toTwilioConfig(
statusPage.callSmsConfig,
),
statusPageId: statusPage.id!,
}).catch((err: Error) => {
logger.error(err);
});
@@ -2417,6 +2486,7 @@ export default class StatusPageAPI extends BaseAPI<
enableEmailSubscribers: true,
enableSmsSubscribers: true,
enableSlackSubscribers: true,
enableMicrosoftTeamsSubscribers: true,
allowSubscribersToChooseResources: true,
allowSubscribersToChooseEventTypes: true,
showSubscriberPageOnStatusPage: true,
@@ -2478,15 +2548,28 @@ export default class StatusPageAPI extends BaseAPI<
}
if (
!req.body.data["subscriberEmail"] &&
!req.body.data["subscriberPhone"] &&
!req.body.data["slackWorkspaceName"]
req.body.data["microsoftTeamsWorkspaceName"] &&
!statusPage.enableMicrosoftTeamsSubscribers
) {
logger.debug(
`No email, phone, or slack workspace name provided for subscription to status page with ID: ${objectId}`,
`Microsoft Teams subscribers not enabled for status page with ID: ${objectId}`,
);
throw new BadDataException(
"Email, phone or slack workspace name is required to subscribe to this status page.",
"Microsoft Teams subscribers not enabled for this status page.",
);
}
if (
!req.body.data["subscriberEmail"] &&
!req.body.data["subscriberPhone"] &&
!req.body.data["slackWorkspaceName"] &&
!req.body.data["microsoftTeamsWorkspaceName"]
) {
logger.debug(
`No email, phone, slack workspace name, or Microsoft Teams workspace name provided for subscription to status page with ID: ${objectId}`,
);
throw new BadDataException(
"Email, phone, slack workspace name, or Microsoft Teams workspace name is required to subscribe to this status page.",
);
}
@@ -2510,6 +2593,18 @@ export default class StatusPageAPI extends BaseAPI<
? (req.body.data["slackWorkspaceName"] as string)
: undefined;
const microsoftTeamsIncomingWebhookUrl: string | undefined = req.body.data[
"microsoftTeamsIncomingWebhookUrl"
]
? (req.body.data["microsoftTeamsIncomingWebhookUrl"] as string)
: undefined;
const microsoftTeamsWorkspaceName: string | undefined = req.body.data[
"microsoftTeamsWorkspaceName"
]
? (req.body.data["microsoftTeamsWorkspaceName"] as string)
: undefined;
let statusPageSubscriber: StatusPageSubscriber | null = null;
let isUpdate: boolean = false;
@@ -2568,6 +2663,23 @@ export default class StatusPageAPI extends BaseAPI<
statusPageSubscriber.slackWorkspaceName = slackWorkspaceName;
}
if (microsoftTeamsIncomingWebhookUrl) {
logger.debug(
`Setting subscriber Microsoft Teams webhook: ${microsoftTeamsIncomingWebhookUrl}`,
);
statusPageSubscriber.microsoftTeamsIncomingWebhookUrl = URL.fromString(
microsoftTeamsIncomingWebhookUrl,
);
}
if (microsoftTeamsWorkspaceName) {
logger.debug(
`Setting subscriber Microsoft Teams workspace name: ${microsoftTeamsWorkspaceName}`,
);
statusPageSubscriber.microsoftTeamsWorkspaceName =
microsoftTeamsWorkspaceName;
}
if (
req.body.data["statusPageResources"] &&
!statusPage.allowSubscribersToChooseResources

View File

@@ -127,9 +127,11 @@ export default class UserPushAPI extends BaseAPI<
},
select: {
userId: true,
deviceName: true,
deviceToken: true,
deviceType: true,
isVerified: true,
projectId: true,
},
});
@@ -174,12 +176,21 @@ export default class UserPushAPI extends BaseAPI<
await PushNotificationService.sendPushNotification(
{
deviceTokens: [device.deviceToken!],
devices: [
{
token: device.deviceToken!,
...(device.deviceName && {
name: device.deviceName,
}),
},
],
message: testMessage,
deviceType: device.deviceType!,
},
{
isSensitive: false,
projectId: device.projectId!,
userId: device.userId!,
},
);

View File

@@ -4,6 +4,7 @@ import {
DashboardRoute,
AppApiRoute,
StatusPageApiRoute,
DocsRoute,
} from "../ServiceRoute";
import BillingConfig from "./BillingConfig";
import Protocol from "../Types/API/Protocol";
@@ -150,6 +151,12 @@ export const AdminDashboardHostname: Hostname = Hostname.fromString(
}`,
);
export const DocsHostname: Hostname = Hostname.fromString(
`${process.env["SERVER_DOCS_HOSTNAME"] || "localhost"}:${
process.env["DOCS_PORT"] || 80
}`,
);
export const Env: string = process.env["NODE_ENV"] || "production";
// Redis does not require password.
@@ -318,6 +325,8 @@ export const AccountsClientUrl: URL = new URL(
AccountsRoute,
);
export const DocsClientUrl: URL = new URL(HttpProtocol, Host, DocsRoute);
export const DisableTelemetry: boolean =
process.env["DISABLE_TELEMETRY"] === "true";

View File

@@ -0,0 +1,67 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754304193228 implements MigrationInterface {
public name = "MigrationName1754304193228";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "ProjectSCIM" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "bearerToken" character varying(500) NOT NULL, "autoProvisionUsers" boolean NOT NULL DEFAULT true, "autoDeprovisionUsers" boolean NOT NULL DEFAULT true, "isEnabled" boolean NOT NULL DEFAULT false, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_51e71d70211675a5c918aee4e68" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_f916360335859c26c4d7051239" ON "ProjectSCIM" ("projectId") `,
);
await queryRunner.query(
`CREATE TABLE "ProjectScimTeam" ("projectScimId" uuid NOT NULL, "teamId" uuid NOT NULL, CONSTRAINT "PK_db724b66b4fa8c880ce5ccf820b" PRIMARY KEY ("projectScimId", "teamId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_b9a28efd66600267f0e9de0731" ON "ProjectScimTeam" ("projectScimId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_bb0eda2ef0c773f975e9ad8448" ON "ProjectScimTeam" ("teamId") `,
);
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" ADD CONSTRAINT "FK_f916360335859c26c4d7051239b" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" ADD CONSTRAINT "FK_5d5d587984f156e5215d51daff7" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" ADD CONSTRAINT "FK_9cadda4fc2af268b5670d02bf76" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "ProjectScimTeam" ADD CONSTRAINT "FK_b9a28efd66600267f0e9de0731b" FOREIGN KEY ("projectScimId") REFERENCES "ProjectSCIM"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "ProjectScimTeam" ADD CONSTRAINT "FK_bb0eda2ef0c773f975e9ad8448a" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "ProjectScimTeam" DROP CONSTRAINT "FK_bb0eda2ef0c773f975e9ad8448a"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectScimTeam" DROP CONSTRAINT "FK_b9a28efd66600267f0e9de0731b"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" DROP CONSTRAINT "FK_9cadda4fc2af268b5670d02bf76"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" DROP CONSTRAINT "FK_5d5d587984f156e5215d51daff7"`,
);
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" DROP CONSTRAINT "FK_f916360335859c26c4d7051239b"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_bb0eda2ef0c773f975e9ad8448"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b9a28efd66600267f0e9de0731"`,
);
await queryRunner.query(`DROP TABLE "ProjectScimTeam"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_f916360335859c26c4d7051239"`,
);
await queryRunner.query(`DROP TABLE "ProjectSCIM"`);
}
}

View File

@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754315774827 implements MigrationInterface {
public name = "MigrationName1754315774827";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" DROP COLUMN "isEnabled"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "ProjectSCIM" ADD "isEnabled" boolean NOT NULL DEFAULT false`,
);
}
}

View File

@@ -0,0 +1,63 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754384418632 implements MigrationInterface {
public name = "MigrationName1754384418632";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "StatusPageSCIM" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "statusPageId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "bearerToken" character varying(500) NOT NULL, "autoProvisionUsers" boolean NOT NULL DEFAULT true, "autoDeprovisionUsers" boolean NOT NULL DEFAULT true, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_9d65d486be515b9608347cf66d4" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_0a241118fe6b4a8665deef444b" ON "StatusPageSCIM" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_7200e368657773fde2836c57eb" ON "StatusPageSCIM" ("statusPageId") `,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" ADD CONSTRAINT "FK_0a241118fe6b4a8665deef444b2" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" ADD CONSTRAINT "FK_7200e368657773fde2836c57ebe" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" ADD CONSTRAINT "FK_adb05dd1cbe0e734a76b3dbdcf1" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" ADD CONSTRAINT "FK_2fded7c784a5c2f56ad2553cb80" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" DROP CONSTRAINT "FK_2fded7c784a5c2f56ad2553cb80"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" DROP CONSTRAINT "FK_adb05dd1cbe0e734a76b3dbdcf1"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" DROP CONSTRAINT "FK_7200e368657773fde2836c57ebe"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSCIM" DROP CONSTRAINT "FK_0a241118fe6b4a8665deef444b2"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_7200e368657773fde2836c57eb"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_0a241118fe6b4a8665deef444b"`,
);
await queryRunner.query(`DROP TABLE "StatusPageSCIM"`);
}
}

View File

@@ -0,0 +1,172 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754671483948 implements MigrationInterface {
public name =
"RenameSubscriberNotificationFailedReasonToStatusMessage1754484441976";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Incident" DROP COLUMN "isStatusPageSubscribersNotifiedOnIncidentCreated"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentPublicNote" DROP COLUMN "isStatusPageSubscribersNotifiedOnNoteCreated"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentStateTimeline" DROP COLUMN "isStatusPageSubscribersNotified"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "isStatusPageSubscribersNotifiedOnEventScheduled"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenancePublicNote" DROP COLUMN "isStatusPageSubscribersNotifiedOnNoteCreated"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenanceStateTimeline" DROP COLUMN "isStatusPageSubscribersNotified"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageAnnouncement" DROP COLUMN "isStatusPageSubscribersNotified"`,
);
await queryRunner.query(
`ALTER TABLE "Incident" ADD "subscriberNotificationStatusOnIncidentCreated" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "Incident" ADD "subscriberNotificationStatusMessage" text`,
);
await queryRunner.query(
`ALTER TABLE "IncidentPublicNote" ADD "subscriberNotificationStatusOnNoteCreated" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "IncidentPublicNote" ADD "subscriberNotificationStatusMessage" text`,
);
await queryRunner.query(
`ALTER TABLE "IncidentStateTimeline" ADD "subscriberNotificationStatus" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "IncidentStateTimeline" ADD "subscriberNotificationStatusMessage" text`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenance" ADD "subscriberNotificationStatusOnEventScheduled" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenance" ADD "subscriberNotificationStatusMessage" text`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenancePublicNote" ADD "subscriberNotificationStatusOnNoteCreated" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenancePublicNote" ADD "subscriberNotificationStatusMessage" text`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenanceStateTimeline" ADD "subscriberNotificationStatus" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenanceStateTimeline" ADD "subscriberNotificationStatusMessage" text`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageAnnouncement" ADD "subscriberNotificationStatus" character varying NOT NULL DEFAULT 'Pending'`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageAnnouncement" ADD "subscriberNotificationStatusMessage" text`,
);
// Set all existing rows' subscriber notification statuses to 'Success' since they were previously considered notified
await queryRunner.query(
`UPDATE "Incident" SET "subscriberNotificationStatusOnIncidentCreated"='Success'`,
);
await queryRunner.query(
`UPDATE "IncidentPublicNote" SET "subscriberNotificationStatusOnNoteCreated"='Success'`,
);
await queryRunner.query(
`UPDATE "IncidentStateTimeline" SET "subscriberNotificationStatus"='Success'`,
);
await queryRunner.query(
`UPDATE "ScheduledMaintenance" SET "subscriberNotificationStatusOnEventScheduled"='Success'`,
);
await queryRunner.query(
`UPDATE "ScheduledMaintenancePublicNote" SET "subscriberNotificationStatusOnNoteCreated"='Success'`,
);
await queryRunner.query(
`UPDATE "ScheduledMaintenanceStateTimeline" SET "subscriberNotificationStatus"='Success'`,
);
await queryRunner.query(
`UPDATE "StatusPageAnnouncement" SET "subscriberNotificationStatus"='Success'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageAnnouncement" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageAnnouncement" DROP COLUMN "subscriberNotificationStatus"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenanceStateTimeline" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenanceStateTimeline" DROP COLUMN "subscriberNotificationStatus"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenancePublicNote" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenancePublicNote" DROP COLUMN "subscriberNotificationStatusOnNoteCreated"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "subscriberNotificationStatusOnEventScheduled"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentStateTimeline" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentStateTimeline" DROP COLUMN "subscriberNotificationStatus"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentPublicNote" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "IncidentPublicNote" DROP COLUMN "subscriberNotificationStatusOnNoteCreated"`,
);
await queryRunner.query(
`ALTER TABLE "Incident" DROP COLUMN "subscriberNotificationStatusMessage"`,
);
await queryRunner.query(
`ALTER TABLE "Incident" DROP COLUMN "subscriberNotificationStatusOnIncidentCreated"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageAnnouncement" ADD "isStatusPageSubscribersNotified" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenanceStateTimeline" ADD "isStatusPageSubscribersNotified" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenancePublicNote" ADD "isStatusPageSubscribersNotifiedOnNoteCreated" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "ScheduledMaintenance" ADD "isStatusPageSubscribersNotifiedOnEventScheduled" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "IncidentStateTimeline" ADD "isStatusPageSubscribersNotified" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "IncidentPublicNote" ADD "isStatusPageSubscribersNotifiedOnNoteCreated" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "Incident" ADD "isStatusPageSubscribersNotifiedOnIncidentCreated" boolean NOT NULL DEFAULT false`,
);
}
}

View File

@@ -0,0 +1,259 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754776130988 implements MigrationInterface {
public name = "MigrationName1754776130988";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "CallLog" ADD "incidentId" uuid`);
await queryRunner.query(`ALTER TABLE "CallLog" ADD "alertId" uuid`);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD "scheduledMaintenanceId" uuid`,
);
await queryRunner.query(`ALTER TABLE "CallLog" ADD "statusPageId" uuid`);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD "statusPageAnnouncementId" uuid`,
);
await queryRunner.query(`ALTER TABLE "EmailLog" ADD "incidentId" uuid`);
await queryRunner.query(`ALTER TABLE "EmailLog" ADD "alertId" uuid`);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD "scheduledMaintenanceId" uuid`,
);
await queryRunner.query(`ALTER TABLE "EmailLog" ADD "statusPageId" uuid`);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD "statusPageAnnouncementId" uuid`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" ADD "incidentId" uuid`);
await queryRunner.query(`ALTER TABLE "SmsLog" ADD "alertId" uuid`);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD "scheduledMaintenanceId" uuid`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" ADD "statusPageId" uuid`);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD "statusPageAnnouncementId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`CREATE INDEX "IDX_a3c1be70374eb2d7bd4197b4e5" ON "CallLog" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_cbcb36c6bf371312ed3b4480d7" ON "CallLog" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_9b351b484c705ed28ff70c63da" ON "CallLog" ("scheduledMaintenanceId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_52a2817222b04d171238c8d26f" ON "CallLog" ("statusPageId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_c97514eeb34172cce672ebc4b4" ON "CallLog" ("statusPageAnnouncementId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_958516eeac015e262300985222" ON "EmailLog" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_41488030fe07b21423bf85c905" ON "EmailLog" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b9230ffb158999e3dc8809f522" ON "EmailLog" ("scheduledMaintenanceId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_8f7cfcce7b39d0f82f6464eb4a" ON "EmailLog" ("statusPageId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a1b7625a277725b4dde4e6914b" ON "EmailLog" ("statusPageAnnouncementId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_4ac2d86e7aa70bc0f7e56c29e8" ON "SmsLog" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_9ba525289a633e16eacc9252ba" ON "SmsLog" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_77668eecd28b8adb9bdef350b3" ON "SmsLog" ("scheduledMaintenanceId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_515845fba2e880ab364efc3f41" ON "SmsLog" ("statusPageId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_42ee5d4d59b6d029610c45b375" ON "SmsLog" ("statusPageAnnouncementId") `,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_a3c1be70374eb2d7bd4197b4e5e" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_cbcb36c6bf371312ed3b4480d7a" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_9b351b484c705ed28ff70c63da5" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_52a2817222b04d171238c8d26fd" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_c97514eeb34172cce672ebc4b40" FOREIGN KEY ("statusPageAnnouncementId") REFERENCES "StatusPageAnnouncement"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_958516eeac015e2623009852228" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_41488030fe07b21423bf85c9058" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_b9230ffb158999e3dc8809f5228" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_8f7cfcce7b39d0f82f6464eb4a4" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_a1b7625a277725b4dde4e6914b2" FOREIGN KEY ("statusPageAnnouncementId") REFERENCES "StatusPageAnnouncement"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_4ac2d86e7aa70bc0f7e56c29e87" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_9ba525289a633e16eacc9252ba3" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_77668eecd28b8adb9bdef350b3b" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_515845fba2e880ab364efc3f414" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_42ee5d4d59b6d029610c45b3757" FOREIGN KEY ("statusPageAnnouncementId") REFERENCES "StatusPageAnnouncement"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_42ee5d4d59b6d029610c45b3757"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_515845fba2e880ab364efc3f414"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_77668eecd28b8adb9bdef350b3b"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_9ba525289a633e16eacc9252ba3"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_4ac2d86e7aa70bc0f7e56c29e87"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_a1b7625a277725b4dde4e6914b2"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_8f7cfcce7b39d0f82f6464eb4a4"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_b9230ffb158999e3dc8809f5228"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_41488030fe07b21423bf85c9058"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_958516eeac015e2623009852228"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_c97514eeb34172cce672ebc4b40"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_52a2817222b04d171238c8d26fd"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_9b351b484c705ed28ff70c63da5"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_cbcb36c6bf371312ed3b4480d7a"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_a3c1be70374eb2d7bd4197b4e5e"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_42ee5d4d59b6d029610c45b375"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_515845fba2e880ab364efc3f41"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_77668eecd28b8adb9bdef350b3"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_9ba525289a633e16eacc9252ba"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_4ac2d86e7aa70bc0f7e56c29e8"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a1b7625a277725b4dde4e6914b"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_8f7cfcce7b39d0f82f6464eb4a"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b9230ffb158999e3dc8809f522"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_41488030fe07b21423bf85c905"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_958516eeac015e262300985222"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c97514eeb34172cce672ebc4b4"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_52a2817222b04d171238c8d26f"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_9b351b484c705ed28ff70c63da"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_cbcb36c6bf371312ed3b4480d7"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a3c1be70374eb2d7bd4197b4e5"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP COLUMN "statusPageAnnouncementId"`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" DROP COLUMN "statusPageId"`);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP COLUMN "scheduledMaintenanceId"`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" DROP COLUMN "alertId"`);
await queryRunner.query(`ALTER TABLE "SmsLog" DROP COLUMN "incidentId"`);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP COLUMN "statusPageAnnouncementId"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP COLUMN "statusPageId"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP COLUMN "scheduledMaintenanceId"`,
);
await queryRunner.query(`ALTER TABLE "EmailLog" DROP COLUMN "alertId"`);
await queryRunner.query(`ALTER TABLE "EmailLog" DROP COLUMN "incidentId"`);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP COLUMN "statusPageAnnouncementId"`,
);
await queryRunner.query(`ALTER TABLE "CallLog" DROP COLUMN "statusPageId"`);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP COLUMN "scheduledMaintenanceId"`,
);
await queryRunner.query(`ALTER TABLE "CallLog" DROP COLUMN "alertId"`);
await queryRunner.query(`ALTER TABLE "CallLog" DROP COLUMN "incidentId"`);
}
}

View File

@@ -0,0 +1,105 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754828812691 implements MigrationInterface {
public name = "MigrationName1754828812691";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "PushNotificationLog" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "title" character varying(500) NOT NULL, "body" text, "deviceType" character varying(100), "statusMessage" character varying(500), "status" character varying(100) NOT NULL, "incidentId" uuid, "alertId" uuid, "scheduledMaintenanceId" uuid, "statusPageId" uuid, "statusPageAnnouncementId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_48b086e2ca3ee9d745ecfe97c41" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_73168664b6ffced71ffa731981" ON "PushNotificationLog" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_59a4b45ae83418ceef477ef459" ON "PushNotificationLog" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_c684177471f5d1a9a3051f21bf" ON "PushNotificationLog" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_5ad3e66a90d721ac387a7da5ca" ON "PushNotificationLog" ("scheduledMaintenanceId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_c48d5589256ff128b0965ab9e7" ON "PushNotificationLog" ("statusPageId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_c62bb260910d202548e36d7827" ON "PushNotificationLog" ("statusPageAnnouncementId") `,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_73168664b6ffced71ffa7319817" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_59a4b45ae83418ceef477ef4590" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_c684177471f5d1a9a3051f21bf0" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_5ad3e66a90d721ac387a7da5caa" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_c48d5589256ff128b0965ab9e78" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_c62bb260910d202548e36d7827a" FOREIGN KEY ("statusPageAnnouncementId") REFERENCES "StatusPageAnnouncement"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_e891a0077d446c86acee230959d" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_e891a0077d446c86acee230959d"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_c62bb260910d202548e36d7827a"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_c48d5589256ff128b0965ab9e78"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_5ad3e66a90d721ac387a7da5caa"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_c684177471f5d1a9a3051f21bf0"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_59a4b45ae83418ceef477ef4590"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_73168664b6ffced71ffa7319817"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c62bb260910d202548e36d7827"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c48d5589256ff128b0965ab9e7"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_5ad3e66a90d721ac387a7da5ca"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c684177471f5d1a9a3051f21bf"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_59a4b45ae83418ceef477ef459"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_73168664b6ffced71ffa731981"`,
);
await queryRunner.query(`DROP TABLE "PushNotificationLog"`);
}
}

View File

@@ -0,0 +1,105 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1754910440587 implements MigrationInterface {
public name = "MigrationName1754910440587";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "WorkspaceNotificationLog" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "workspaceType" character varying(100) NOT NULL, "channelId" character varying(100), "channelName" character varying(100), "threadId" character varying(100), "messageSummary" character varying(500), "statusMessage" character varying(500), "status" character varying(100) NOT NULL, "incidentId" uuid, "alertId" uuid, "scheduledMaintenanceId" uuid, "statusPageId" uuid, "statusPageAnnouncementId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_8017cedff7ab932c1dc3d9c4c5f" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_88e90b94233cbe8563a4bbfe45" ON "WorkspaceNotificationLog" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_872f735f983a70558c79c78ab7" ON "WorkspaceNotificationLog" ("incidentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_346cb35ed758bd44e1e6e7405e" ON "WorkspaceNotificationLog" ("alertId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_31bc9b6754310f914c30e074d0" ON "WorkspaceNotificationLog" ("scheduledMaintenanceId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_ef2bf686464a74e9d759630b02" ON "WorkspaceNotificationLog" ("statusPageId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_bf6998abfbf0786aeeb870756f" ON "WorkspaceNotificationLog" ("statusPageAnnouncementId") `,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_88e90b94233cbe8563a4bbfe45a" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_872f735f983a70558c79c78ab71" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_346cb35ed758bd44e1e6e7405eb" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_31bc9b6754310f914c30e074d00" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_ef2bf686464a74e9d759630b02a" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_bf6998abfbf0786aeeb870756f8" FOREIGN KEY ("statusPageAnnouncementId") REFERENCES "StatusPageAnnouncement"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_a99d29c3dfd37e7d2838436f702" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_a99d29c3dfd37e7d2838436f702"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_bf6998abfbf0786aeeb870756f8"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_ef2bf686464a74e9d759630b02a"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_31bc9b6754310f914c30e074d00"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_346cb35ed758bd44e1e6e7405eb"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_872f735f983a70558c79c78ab71"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_88e90b94233cbe8563a4bbfe45a"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_bf6998abfbf0786aeeb870756f"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_ef2bf686464a74e9d759630b02"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_31bc9b6754310f914c30e074d0"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_346cb35ed758bd44e1e6e7405e"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_872f735f983a70558c79c78ab7"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_88e90b94233cbe8563a4bbfe45"`,
);
await queryRunner.query(`DROP TABLE "WorkspaceNotificationLog"`);
}
}

View File

@@ -0,0 +1,101 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755030730926 implements MigrationInterface {
public name = "MigrationName1755030730926";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "CallLog" ADD "userId" uuid`);
await queryRunner.query(`ALTER TABLE "EmailLog" ADD "userId" uuid`);
await queryRunner.query(`ALTER TABLE "SmsLog" ADD "userId" uuid`);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD "userId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "userId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`CREATE INDEX "IDX_47f0ed650c5e09da943caea60c" ON "CallLog" ("userId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_d1fb84d0e16365609457eb1c7b" ON "EmailLog" ("userId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a2d58057bf9933c84b4fb0bafd" ON "SmsLog" ("userId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_6da1247dee5e3bfa4cfd4d11ed" ON "PushNotificationLog" ("userId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_0debc118df807b42cb4b274ff8" ON "WorkspaceNotificationLog" ("userId") `,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_47f0ed650c5e09da943caea60c3" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_d1fb84d0e16365609457eb1c7ba" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_a2d58057bf9933c84b4fb0bafda" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_6da1247dee5e3bfa4cfd4d11ed6" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_0debc118df807b42cb4b274ff89" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_0debc118df807b42cb4b274ff89"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_6da1247dee5e3bfa4cfd4d11ed6"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_a2d58057bf9933c84b4fb0bafda"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_d1fb84d0e16365609457eb1c7ba"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_47f0ed650c5e09da943caea60c3"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_0debc118df807b42cb4b274ff8"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_6da1247dee5e3bfa4cfd4d11ed"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a2d58057bf9933c84b4fb0bafd"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_d1fb84d0e16365609457eb1c7b"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_47f0ed650c5e09da943caea60c"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "userId"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP COLUMN "userId"`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" DROP COLUMN "userId"`);
await queryRunner.query(`ALTER TABLE "EmailLog" DROP COLUMN "userId"`);
await queryRunner.query(`ALTER TABLE "CallLog" DROP COLUMN "userId"`);
}
}

View File

@@ -0,0 +1,371 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755088852971 implements MigrationInterface {
public name = "MigrationName1755088852971";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "CallLog" ADD "onCallDutyPolicyId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD "onCallDutyPolicyEscalationRuleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD "onCallDutyPolicyScheduleId" uuid`,
);
await queryRunner.query(`ALTER TABLE "CallLog" ADD "teamId" uuid`);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD "onCallDutyPolicyId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD "onCallDutyPolicyEscalationRuleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD "onCallDutyPolicyScheduleId" uuid`,
);
await queryRunner.query(`ALTER TABLE "EmailLog" ADD "teamId" uuid`);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD "onCallDutyPolicyId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD "onCallDutyPolicyEscalationRuleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD "onCallDutyPolicyScheduleId" uuid`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" ADD "teamId" uuid`);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD "onCallDutyPolicyId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD "onCallDutyPolicyEscalationRuleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD "onCallDutyPolicyScheduleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD "teamId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "onCallDutyPolicyId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "onCallDutyPolicyEscalationRuleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "onCallDutyPolicyScheduleId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "teamId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`CREATE INDEX "IDX_6946bee33de8b45b86ebb0012e" ON "CallLog" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_80d91b1551ba233574c0bcb622" ON "CallLog" ("onCallDutyPolicyEscalationRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_cd59580cf3a63b448174a1137d" ON "CallLog" ("onCallDutyPolicyScheduleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_05936c8c2d09e1d8b9e0ae4401" ON "CallLog" ("teamId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_556a159f8352d88297a8d3e951" ON "EmailLog" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b7304fe2449af401fb07cc8b1c" ON "EmailLog" ("onCallDutyPolicyEscalationRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_e8c3faceca2821e87fcccd43d2" ON "EmailLog" ("onCallDutyPolicyScheduleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_e394d08e87fb40b3a5d0b91250" ON "EmailLog" ("teamId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_e40b9d395423a1f4426cf43bd8" ON "SmsLog" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_31ebe9573e70ab953299403142" ON "SmsLog" ("onCallDutyPolicyEscalationRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_45577c7db6091e91e99d492854" ON "SmsLog" ("onCallDutyPolicyScheduleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_ea4117e6437e6ea9a742dd978b" ON "SmsLog" ("teamId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a2439761a3dbd16c5944743690" ON "PushNotificationLog" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a75ab085a0a948e113e120c468" ON "PushNotificationLog" ("onCallDutyPolicyEscalationRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b7709c3c7792047a57c4e3c090" ON "PushNotificationLog" ("onCallDutyPolicyScheduleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_dba4c943614d8fa262ca2f39bf" ON "PushNotificationLog" ("teamId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_bfe40c4a4b25d4d68d53879f30" ON "WorkspaceNotificationLog" ("onCallDutyPolicyId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_8a1696a130d26efe72b215a1a7" ON "WorkspaceNotificationLog" ("onCallDutyPolicyEscalationRuleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b8212e8152d5b38c1d5d284fc9" ON "WorkspaceNotificationLog" ("onCallDutyPolicyScheduleId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_3881ce57f0bb88894ea33b77b1" ON "WorkspaceNotificationLog" ("teamId") `,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_6946bee33de8b45b86ebb0012e8" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_80d91b1551ba233574c0bcb622a" FOREIGN KEY ("onCallDutyPolicyEscalationRuleId") REFERENCES "OnCallDutyPolicyEscalationRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_cd59580cf3a63b448174a1137d5" FOREIGN KEY ("onCallDutyPolicyScheduleId") REFERENCES "OnCallDutyPolicySchedule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" ADD CONSTRAINT "FK_05936c8c2d09e1d8b9e0ae4401d" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_556a159f8352d88297a8d3e951f" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_b7304fe2449af401fb07cc8b1ce" FOREIGN KEY ("onCallDutyPolicyEscalationRuleId") REFERENCES "OnCallDutyPolicyEscalationRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_e8c3faceca2821e87fcccd43d28" FOREIGN KEY ("onCallDutyPolicyScheduleId") REFERENCES "OnCallDutyPolicySchedule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" ADD CONSTRAINT "FK_e394d08e87fb40b3a5d0b912505" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_e40b9d395423a1f4426cf43bd8a" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_31ebe9573e70ab9532994031422" FOREIGN KEY ("onCallDutyPolicyEscalationRuleId") REFERENCES "OnCallDutyPolicyEscalationRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_45577c7db6091e91e99d492854b" FOREIGN KEY ("onCallDutyPolicyScheduleId") REFERENCES "OnCallDutyPolicySchedule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" ADD CONSTRAINT "FK_ea4117e6437e6ea9a742dd978b3" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_a2439761a3dbd16c59447436905" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_a75ab085a0a948e113e120c468e" FOREIGN KEY ("onCallDutyPolicyEscalationRuleId") REFERENCES "OnCallDutyPolicyEscalationRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_b7709c3c7792047a57c4e3c0904" FOREIGN KEY ("onCallDutyPolicyScheduleId") REFERENCES "OnCallDutyPolicySchedule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD CONSTRAINT "FK_dba4c943614d8fa262ca2f39bf2" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_bfe40c4a4b25d4d68d53879f30d" FOREIGN KEY ("onCallDutyPolicyId") REFERENCES "OnCallDutyPolicy"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_8a1696a130d26efe72b215a1a78" FOREIGN KEY ("onCallDutyPolicyEscalationRuleId") REFERENCES "OnCallDutyPolicyEscalationRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_b8212e8152d5b38c1d5d284fc9e" FOREIGN KEY ("onCallDutyPolicyScheduleId") REFERENCES "OnCallDutyPolicySchedule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD CONSTRAINT "FK_3881ce57f0bb88894ea33b77b17" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_3881ce57f0bb88894ea33b77b17"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_b8212e8152d5b38c1d5d284fc9e"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_8a1696a130d26efe72b215a1a78"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP CONSTRAINT "FK_bfe40c4a4b25d4d68d53879f30d"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_dba4c943614d8fa262ca2f39bf2"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_b7709c3c7792047a57c4e3c0904"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_a75ab085a0a948e113e120c468e"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP CONSTRAINT "FK_a2439761a3dbd16c59447436905"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_ea4117e6437e6ea9a742dd978b3"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_45577c7db6091e91e99d492854b"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_31ebe9573e70ab9532994031422"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP CONSTRAINT "FK_e40b9d395423a1f4426cf43bd8a"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_e394d08e87fb40b3a5d0b912505"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_e8c3faceca2821e87fcccd43d28"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_b7304fe2449af401fb07cc8b1ce"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP CONSTRAINT "FK_556a159f8352d88297a8d3e951f"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_05936c8c2d09e1d8b9e0ae4401d"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_cd59580cf3a63b448174a1137d5"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_80d91b1551ba233574c0bcb622a"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP CONSTRAINT "FK_6946bee33de8b45b86ebb0012e8"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_3881ce57f0bb88894ea33b77b1"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b8212e8152d5b38c1d5d284fc9"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_8a1696a130d26efe72b215a1a7"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_bfe40c4a4b25d4d68d53879f30"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_dba4c943614d8fa262ca2f39bf"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b7709c3c7792047a57c4e3c090"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a75ab085a0a948e113e120c468"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a2439761a3dbd16c5944743690"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_ea4117e6437e6ea9a742dd978b"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_45577c7db6091e91e99d492854"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_31ebe9573e70ab953299403142"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_e40b9d395423a1f4426cf43bd8"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_e394d08e87fb40b3a5d0b91250"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_e8c3faceca2821e87fcccd43d2"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b7304fe2449af401fb07cc8b1c"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_556a159f8352d88297a8d3e951"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_05936c8c2d09e1d8b9e0ae4401"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_cd59580cf3a63b448174a1137d"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_80d91b1551ba233574c0bcb622"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_6946bee33de8b45b86ebb0012e"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "teamId"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "onCallDutyPolicyScheduleId"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "onCallDutyPolicyEscalationRuleId"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "onCallDutyPolicyId"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP COLUMN "teamId"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP COLUMN "onCallDutyPolicyScheduleId"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP COLUMN "onCallDutyPolicyEscalationRuleId"`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP COLUMN "onCallDutyPolicyId"`,
);
await queryRunner.query(`ALTER TABLE "SmsLog" DROP COLUMN "teamId"`);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP COLUMN "onCallDutyPolicyScheduleId"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP COLUMN "onCallDutyPolicyEscalationRuleId"`,
);
await queryRunner.query(
`ALTER TABLE "SmsLog" DROP COLUMN "onCallDutyPolicyId"`,
);
await queryRunner.query(`ALTER TABLE "EmailLog" DROP COLUMN "teamId"`);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP COLUMN "onCallDutyPolicyScheduleId"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP COLUMN "onCallDutyPolicyEscalationRuleId"`,
);
await queryRunner.query(
`ALTER TABLE "EmailLog" DROP COLUMN "onCallDutyPolicyId"`,
);
await queryRunner.query(`ALTER TABLE "CallLog" DROP COLUMN "teamId"`);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP COLUMN "onCallDutyPolicyScheduleId"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP COLUMN "onCallDutyPolicyEscalationRuleId"`,
);
await queryRunner.query(
`ALTER TABLE "CallLog" DROP COLUMN "onCallDutyPolicyId"`,
);
}
}

View File

@@ -0,0 +1,29 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755093133870 implements MigrationInterface {
public name = "MigrationName1755093133870";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "actionType" character varying(100) NOT NULL DEFAULT 'SendMessage'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "actionType"`,
);
}
}

View File

@@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755109893911 implements MigrationInterface {
public name = "MigrationName1755109893911";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" ADD "deviceName" character varying(100)`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ALTER COLUMN "actionType" SET DEFAULT 'SendMessage'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ALTER COLUMN "actionType" SET DEFAULT 'MessageSent'`,
);
await queryRunner.query(
`ALTER TABLE "PushNotificationLog" DROP COLUMN "deviceName"`,
);
}
}

View File

@@ -0,0 +1,41 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755110936888 implements MigrationInterface {
public name = "MigrationName1755110936888";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" RENAME COLUMN "messageSummary" TO "message"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "message"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "message" text`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" DROP COLUMN "message"`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" ADD "message" character varying(500)`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "WorkspaceNotificationLog" RENAME COLUMN "message" TO "messageSummary"`,
);
}
}

View File

@@ -0,0 +1,29 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755775040650 implements MigrationInterface {
public name = "MigrationName1755775040650";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "StatusPage" ADD "enableMicrosoftTeamsSubscribers" boolean NOT NULL DEFAULT false`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" ADD "microsoftTeamsIncomingWebhookUrl" character varying`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" ADD "microsoftTeamsWorkspaceName" character varying(100)`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "microsoftTeamsWorkspaceName"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "microsoftTeamsIncomingWebhookUrl"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPage" DROP COLUMN "enableMicrosoftTeamsSubscribers"`,
);
}
}

View File

@@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755778495455 implements MigrationInterface {
public name = "MigrationName1755778495455";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "microsoftTeamsWorkspaceName"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" ADD "microsoftTeamsWorkspaceName" text`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "microsoftTeamsWorkspaceName"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" ADD "microsoftTeamsWorkspaceName" character varying(100)`,
);
}
}

View File

@@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1755778934927 implements MigrationInterface {
public name = "MigrationName1755778934927";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "microsoftTeamsIncomingWebhookUrl"`,
);
await queryRunner.query(
`ALTER TABLE "StatusPageSubscriber" ADD "microsoftTeamsIncomingWebhookUrl" text`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
}
}

View File

@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1756293325324 implements MigrationInterface {
public name = "MigrationName1756293325324";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" ADD "businessDetails" character varying(500)`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" DROP COLUMN "businessDetails"`,
);
}
}

View File

@@ -0,0 +1,29 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1756296282627 implements MigrationInterface {
public name = "MigrationName1756296282627";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" ADD "businessDetailsCountry" character varying(100)`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "Project" DROP COLUMN "businessDetailsCountry"`,
);
}
}

View File

@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1756300358095 implements MigrationInterface {
public name = "MigrationName1756300358095";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" ADD "financeAccountingEmail" character varying(100)`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" DROP COLUMN "financeAccountingEmail"`,
);
}
}

View File

@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1756821449686 implements MigrationInterface {
public name = "MigrationName1756821449686";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" ADD "doNotAddGlobalProbesByDefaultOnNewMonitors" boolean NOT NULL DEFAULT false`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" DROP COLUMN "doNotAddGlobalProbesByDefaultOnNewMonitors"`,
);
}
}

View File

@@ -0,0 +1,41 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1757416939595 implements MigrationInterface {
public name = "MigrationName1757416939595";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "IncidentTemplate" ADD "initialIncidentStateId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`CREATE INDEX "IDX_36317c99429a40d3344d838223" ON "IncidentTemplate" ("initialIncidentStateId") `,
);
await queryRunner.query(
`ALTER TABLE "IncidentTemplate" ADD CONSTRAINT "FK_36317c99429a40d3344d838223f" FOREIGN KEY ("initialIncidentStateId") REFERENCES "IncidentState"("_id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "IncidentTemplate" DROP CONSTRAINT "FK_36317c99429a40d3344d838223f"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_36317c99429a40d3344d838223"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "IncidentTemplate" DROP COLUMN "initialIncidentStateId"`,
);
}
}

View File

@@ -0,0 +1,79 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1757423505855 implements MigrationInterface {
public name = "MigrationName1757423505855";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "AnnouncementMonitor" ("announcementId" uuid NOT NULL, "monitorId" uuid NOT NULL, CONSTRAINT "PK_7acb54ddede76e67b5e2eb84519" PRIMARY KEY ("announcementId", "monitorId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_b43baa07f7be40b5cfb61153fd" ON "AnnouncementMonitor" ("announcementId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_751be8c61cfeb7e1a0af9fcc3a" ON "AnnouncementMonitor" ("monitorId") `,
);
await queryRunner.query(
`CREATE TABLE "AnnouncementTemplateMonitor" ("announcementTemplateId" uuid NOT NULL, "monitorId" uuid NOT NULL, CONSTRAINT "PK_ad19f2b65c1b6b77e7a8d80c028" PRIMARY KEY ("announcementTemplateId", "monitorId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_46bee9106e631ebe9f6c95ff15" ON "AnnouncementTemplateMonitor" ("announcementTemplateId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_0d979cb538fde87c7441d7bc93" ON "AnnouncementTemplateMonitor" ("monitorId") `,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementMonitor" ADD CONSTRAINT "FK_b43baa07f7be40b5cfb61153fd3" FOREIGN KEY ("announcementId") REFERENCES "StatusPageAnnouncement"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementMonitor" ADD CONSTRAINT "FK_751be8c61cfeb7e1a0af9fcc3a0" FOREIGN KEY ("monitorId") REFERENCES "Monitor"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementTemplateMonitor" ADD CONSTRAINT "FK_46bee9106e631ebe9f6c95ff153" FOREIGN KEY ("announcementTemplateId") REFERENCES "StatusPageAnnouncementTemplate"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementTemplateMonitor" ADD CONSTRAINT "FK_0d979cb538fde87c7441d7bc936" FOREIGN KEY ("monitorId") REFERENCES "Monitor"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "AnnouncementTemplateMonitor" DROP CONSTRAINT "FK_0d979cb538fde87c7441d7bc936"`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementTemplateMonitor" DROP CONSTRAINT "FK_46bee9106e631ebe9f6c95ff153"`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementMonitor" DROP CONSTRAINT "FK_751be8c61cfeb7e1a0af9fcc3a0"`,
);
await queryRunner.query(
`ALTER TABLE "AnnouncementMonitor" DROP CONSTRAINT "FK_b43baa07f7be40b5cfb61153fd3"`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
);
await queryRunner.query(
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_0d979cb538fde87c7441d7bc93"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_46bee9106e631ebe9f6c95ff15"`,
);
await queryRunner.query(`DROP TABLE "AnnouncementTemplateMonitor"`);
await queryRunner.query(
`DROP INDEX "public"."IDX_751be8c61cfeb7e1a0af9fcc3a"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b43baa07f7be40b5cfb61153fd"`,
);
await queryRunner.query(`DROP TABLE "AnnouncementMonitor"`);
}
}

View File

@@ -146,6 +146,27 @@ import { MigrationName1753343522987 } from "./1753343522987-MigrationName";
import { MigrationName1753377161288 } from "./1753377161288-MigrationName";
import { AddPerformanceIndexes1753378524062 } from "./1753378524062-AddPerformanceIndexes";
import { MigrationName1753383711511 } from "./1753383711511-MigrationName";
import { MigrationName1754304193228 } from "./1754304193228-MigrationName";
import { MigrationName1754315774827 } from "./1754315774827-MigrationName";
import { MigrationName1754384418632 } from "./1754384418632-MigrationName";
import { MigrationName1754671483948 } from "./1754671483948-MigrationName";
import { MigrationName1754776130988 } from "./1754776130988-MigrationName";
import { MigrationName1754828812691 } from "./1754828812691-MigrationName";
import { MigrationName1754910440587 } from "./1754910440587-MigrationName";
import { MigrationName1755030730926 } from "./1755030730926-MigrationName";
import { MigrationName1755088852971 } from "./1755088852971-MigrationName";
import { MigrationName1755093133870 } from "./1755093133870-MigrationName";
import { MigrationName1755109893911 } from "./1755109893911-MigrationName";
import { MigrationName1755110936888 } from "./1755110936888-MigrationName";
import { MigrationName1755775040650 } from "./1755775040650-MigrationName";
import { MigrationName1755778495455 } from "./1755778495455-MigrationName";
import { MigrationName1755778934927 } from "./1755778934927-MigrationName";
import { MigrationName1756293325324 } from "./1756293325324-MigrationName";
import { MigrationName1756296282627 } from "./1756296282627-MigrationName";
import { MigrationName1756300358095 } from "./1756300358095-MigrationName";
import { MigrationName1756821449686 } from "./1756821449686-MigrationName";
import { MigrationName1757416939595 } from "./1757416939595-MigrationName";
import { MigrationName1757423505855 } from "./1757423505855-MigrationName";
export default [
InitialMigration,
@@ -296,4 +317,25 @@ export default [
MigrationName1753377161288,
AddPerformanceIndexes1753378524062,
MigrationName1753383711511,
MigrationName1754304193228,
MigrationName1754315774827,
MigrationName1754384418632,
MigrationName1754671483948,
MigrationName1754776130988,
MigrationName1754828812691,
MigrationName1754910440587,
MigrationName1755030730926,
MigrationName1755088852971,
MigrationName1755093133870,
MigrationName1755109893911,
MigrationName1755110936888,
MigrationName1755775040650,
MigrationName1755778495455,
MigrationName1755778934927,
MigrationName1756293325324,
MigrationName1756296282627,
MigrationName1756300358095,
MigrationName1756821449686,
MigrationName1757416939595,
MigrationName1757423505855,
];

Some files were not shown because too many files have changed in this diff Show More