Compare commits

...

496 Commits

Author SHA1 Message Date
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
Simon Larsen
a7014ac3ff fix: update projectId handling to ensure proper ObjectID conversion in telemetry processing 2025-07-30 16:12:19 +01:00
Simon Larsen
fa31dc670c feat: implement telemetry ingestion processing with queue integration 2025-07-30 15:37:08 +01:00
Simon Larsen
4c2a12cf31 feat: add queue stats and size endpoints with authorization middleware 2025-07-30 15:34:51 +01:00
Simon Larsen
b4115e1529 feat: initialize telemetry processing worker with logging for better monitoring 2025-07-30 15:30:23 +01:00
Simon Larsen
3883790c50 feat: add getQueueSize and getQueueStats methods to Queue class for improved queue monitoring 2025-07-30 15:29:53 +01:00
Simon Larsen
1702558d73 chore: update package-lock.json files to add @types/web-push and web-push dependencies
- Added "@types/web-push": "^3.6.4" to multiple package-lock.json files.
- Added "web-push": "^3.6.7" to multiple package-lock.json files.
- Removed "lodash" and "@types/lodash" from multiple package-lock.json files.
2025-07-30 15:21:03 +01:00
Simon Larsen
cacdbff50e Implement feature X to enhance user experience and optimize performance 2025-07-30 13:58:46 +01:00
Nawaz Dhandala
0bc6b432a2 refactor: Update getNestedValue function signature for improved type safety in Detail and TableRow components 2025-07-30 13:57:23 +01:00
Simon Larsen
eaa09d4a13 refactor: Replace lodash get with custom nested value helper in Detail and TableRow components 2025-07-30 13:52:30 +01:00
Simon Larsen
08c85dd31c refactor: Remove lodash and its type definitions from package dependencies 2025-07-30 12:48:19 +01:00
Nawaz Dhandala
42e82b6fb7 refactor: Clean up whitespace in various components for improved readability 2025-07-30 12:08:53 +01:00
Simon Larsen
463a20f342 feat: Add ingestedAt timestamp to ProbeMonitorResponse and update ingestion logic 2025-07-30 12:08:21 +01:00
Simon Larsen
1b8a7e3261 chore: Add sw.js to .gitignore to prevent tracking of service worker file 2025-07-30 11:23:26 +01:00
Simon Larsen
8b27dd1f26 refactor: Remove deprecated service worker implementation from Dashboard 2025-07-30 11:23:09 +01:00
Simon Larsen
17c72f65e3 refactor: Update service worker template and generated version information for Dashboard 2025-07-30 11:22:29 +01:00
Simon Larsen
5eee900fd3 feat: Implement service worker generation script and update build process for Dashboard 2025-07-30 11:18:55 +01:00
Simon Larsen
0a6cdd11af refactor: Simplify esbuild configuration by disabling minification and removing build version generation 2025-07-30 10:47:23 +01:00
Simon Larsen
8514b6b82e refactor: Enhance PWA service worker with caching strategies and update notifications 2025-07-30 10:45:18 +01:00
Simon Larsen
dfa8f6cd24 refactor: Remove unused LocalStorage import and update status page ID handling in DashboardMasterPage 2025-07-30 10:41:19 +01:00
Simon Larsen
61614227e1 refactor: Update dependency version for @oneuptime/common to allow any version 2025-07-30 10:01:46 +01:00
Simon Larsen
f3d20eb544 refactor: Add spacing before nav element in Pagination component for improved layout 2025-07-29 13:47:33 +01:00
Simon Larsen
a11ff57fda refactor: Clean up layout in Pagination component with improved mobile navigation and added comments for clarity 2025-07-29 13:46:23 +01:00
Simon Larsen
deb635bc80 refactor: Remove unnecessary height style from Modal component for improved responsiveness 2025-07-29 11:25:26 +01:00
Simon Larsen
c707830811 refactor: Adjust margin for label in ProbePicker component for better alignment 2025-07-29 11:20:28 +01:00
Nawaz Dhandala
24ada68d1e refactor: Replace lodash Dictionary import with local Dictionary type in multiple files 2025-07-29 11:12:37 +01:00
Nawaz Dhandala
ca23234ba9 refactor: Update import statement for Dictionary in Route.ts 2025-07-29 11:10:22 +01:00
Nawaz Dhandala
ea40a955e9 refactor: Enhance Slack notification structure for balance refill in NotificationService 2025-07-29 11:07:56 +01:00
Nawaz Dhandala
a46ee07d70 refactor: Format imports and improve error logging in NotificationService 2025-07-29 11:07:10 +01:00
Simon Larsen
5c5bab408d refactor: Simplify Terraform examples by removing unused monitor configurations and variables 2025-07-29 11:02:57 +01:00
Simon Larsen
540d632baf feat: Add Slack notification for balance refill in NotificationService 2025-07-28 12:03:40 +01:00
Simon Larsen
74718017ad refactor: Update jest.config.json for module name mapping and transform ignore patterns 2025-07-25 16:03:01 +01:00
Simon Larsen
d16897db1b refactor: update dependencies in package.json
- Replaced "Common" dependency with "@oneuptime/common" version 7.0.4773.
- Maintained existing versions for "dotenv" and "ts-node".
2025-07-25 15:38:07 +01:00
Simon Larsen
be3fc6f077 refactor: Update monitorTask type from PromiseVoidFunction to Promise<void> for consistency 2025-07-25 14:37:52 +01:00
Nawaz Dhandala
b7b577517c refactor: Improve type safety by defining PromiseVoidFunction for monitorTask in CheckOnlineStatus 2025-07-25 14:34:04 +01:00
Simon Larsen
ccf7a96e43 refactor: Streamline monitor processing logic in CheckOnlineStatus for improved error handling and parallel execution 2025-07-25 14:26:54 +01:00
Simon Larsen
892f3c052a feat: Add timeNow property to ServerMonitorResponse and update related logic in ServerMonitorCriteria and CheckOnlineStatus 2025-07-25 14:25:01 +01:00
Simon Larsen
00833a06f4 fix: Update time calculation in CheckOnlineStatus to use three minutes ago 2025-07-25 14:20:32 +01:00
Simon Larsen
472adf610a refactor: Update comment to clarify SSL monitor check in MonitorResourceUtil 2025-07-25 14:14:12 +01:00
Nawaz Dhandala
976c36de9a feat: Add migration for new default values and indexes in OnCallDutyPolicyScheduleLayer 2025-07-25 13:50:08 +01:00
Simon Larsen
6026c9c9af refactor: Remove unused import for ProbeApiIngestResponse in ServerMonitor.ts 2025-07-25 13:49:34 +01:00
Simon Larsen
791aa1421b feat: Optimize server monitor response handling by returning early and streamlining processing 2025-07-25 13:49:14 +01:00
Simon Larsen
79dbc94f82 feat: Add log viewing instructions and improve error logging in agent 2025-07-25 13:42:25 +01:00
Simon Larsen
ded41fc7ec feat: Enhance logging functionality with log file path configuration and log directory management 2025-07-25 13:38:23 +01:00
Simon Larsen
581c374745 refactor: Remove PWA install prompt to streamline user experience 2025-07-25 13:31:26 +01:00
Simon Larsen
64c0c8b4cb haraka delete 2025-07-25 09:07:09 +01:00
Simon Larsen
7d2241ba98 feat: Add indexes to improve query performance across multiple database models 2025-07-24 20:02:23 +01:00
Nawaz Dhandala
30bada5b7a feat: Add additional performance indexes and update migration index list 2025-07-24 18:40:40 +01:00
Simon Larsen
61bfb37747 Merge branch 'release' of github.com:OneUptime/oneuptime into release 2025-07-24 18:39:42 +01:00
Simon Larsen
4686aa941a feat: Add performance indexes to improve query efficiency across multiple database models 2025-07-24 18:39:04 +01:00
Nawaz Dhandala
3c065c76b0 feat: Add missing indexes for improved query performance in IncidentStateTimeline and MonitorProbe 2025-07-24 18:26:03 +01:00
Simon Larsen
5dccd03ed4 refactor: Remove ProcessMetrics job to streamline monitor metric handling 2025-07-24 18:16:32 +01:00
Simon Larsen
a395a95997 feat: Add composite indexes for efficient querying in IncidentStateTimeline, MonitorProbe, and MonitorStatusTimeline 2025-07-24 18:16:06 +01:00
Nawaz Dhandala
89082b1232 refactor: Improve error handling and type definitions in core operations across multiple services 2025-07-24 17:42:38 +01:00
Nawaz Dhandala
7cb33de450 refactor: Enhance error handling and type definitions in core operations for AlertService and IncidentService 2025-07-24 17:34:46 +01:00
Nawaz Dhandala
353ac875fb refactor: Simplify promise handling and error logging in service operations 2025-07-24 17:25:54 +01:00
Simon Larsen
d6560fdb32 feat: Refactor incident creation to execute core operations asynchronously 2025-07-24 17:23:53 +01:00
Simon Larsen
5115e21a7a feat: Refactor scheduled maintenance creation to execute core operations asynchronously 2025-07-24 17:17:52 +01:00
Simon Larsen
0e6119ddce feat: Execute owner assignment asynchronously in StatusPageService 2025-07-24 17:14:46 +01:00
Simon Larsen
b842a49cfb feat: Refactor monitor creation to run core operations in parallel, deferring workspace operations 2025-07-24 16:42:29 +01:00
Nawaz Dhandala
9737e50467 refactor: Clean up whitespace and improve code formatting in migration and service files 2025-07-24 16:00:49 +01:00
Simon Larsen
91beb6091d feat: Optimize monitor creation by parallelizing workspace, billing, and probe operations 2025-07-24 15:56:35 +01:00
Simon Larsen
68e610aa9f fix: Disable workflow operations for MetricType entity 2025-07-24 15:25:04 +01:00
Simon Larsen
d673ef3a01 feat: Enhance memory management and error handling in telemetry ingestion processes 2025-07-24 15:22:29 +01:00
494 changed files with 37450 additions and 20794 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,23 +255,11 @@ jobs:
# build image for home
- name: build docker image
run: sudo docker build -f ./Dashboard/Dockerfile .
docker-build-haraka:
runs-on: ubuntu-latest
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Preinstall
run: npm run prerun
# build images
- name: build docker image
run: sudo docker build -f ./Haraka/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
@@ -238,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
@@ -253,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
@@ -268,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
@@ -283,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
@@ -298,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
@@ -313,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
@@ -328,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
@@ -343,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

View File

@@ -70,7 +70,7 @@ jobs:
publish-mcp-server:
runs-on: ubuntu-latest
needs: [generate-build-number]
needs: [generate-build-number, publish-npm-packages]
env:
CI_PIPELINE_ID: ${{ github.run_number }}
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
@@ -138,6 +138,7 @@ jobs:
- name: Install dependencies
run: |
cd MCP
npm update @oneuptime/common
npm install
- name: Build MCP server
@@ -183,18 +184,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker images
run: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file ./MCP/Dockerfile.tpl \
--tag oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag oneuptime/mcp-server:release \
--tag ghcr.io/oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag ghcr.io/oneuptime/mcp-server:release \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=${{ steps.version.outputs.version }} \
--push .
echo "✅ Pushed Docker images to Docker Hub and GitHub Container Registry"
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file ./MCP/Dockerfile.tpl \
--tag oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag oneuptime/mcp-server:release \
--tag ghcr.io/oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag ghcr.io/oneuptime/mcp-server:release \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=${{ steps.version.outputs.version }} \
--push .
echo "✅ Pushed Docker images to Docker Hub and GitHub Container Registry"
- name: Upload MCP server artifact
uses: actions/upload-artifact@v4
@@ -251,17 +256,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Nginx/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Nginx/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/nginx:release \
--tag oneuptime/nginx:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/nginx:release \
--tag ghcr.io/oneuptime/nginx:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
e2e-docker-image-deploy:
needs: [generate-build-number]
@@ -311,17 +321,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./E2E/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./E2E/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/e2e:release \
--tag oneuptime/e2e:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/e2e:release \
--tag ghcr.io/oneuptime/e2e:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
isolated-vm-docker-image-deploy:
needs: [generate-build-number]
@@ -371,17 +386,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./IsolatedVM/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./IsolatedVM/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/isolated-vm:release \
--tag oneuptime/isolated-vm:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/isolated-vm:release \
--tag ghcr.io/oneuptime/isolated-vm:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
home-docker-image-deploy:
needs: [generate-build-number]
@@ -431,17 +451,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Home/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Home/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/home:release \
--tag oneuptime/home:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/home:release \
--tag ghcr.io/oneuptime/home:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -494,17 +519,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./TestServer/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./TestServer/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/test-server:release \
--tag oneuptime/test-server:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/test-server:release \
--tag ghcr.io/oneuptime/test-server:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
otel-collector-docker-image-deploy:
needs: [generate-build-number]
@@ -554,17 +584,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./OTelCollector/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./OTelCollector/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/otel-collector:release \
--tag oneuptime/otel-collector:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/otel-collector:release \
--tag ghcr.io/oneuptime/otel-collector:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -616,17 +651,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./StatusPage/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./StatusPage/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/status-page:release \
--tag oneuptime/status-page:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/status-page:release \
--tag ghcr.io/oneuptime/status-page:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
test-docker-image-deploy:
needs: [generate-build-number]
@@ -676,17 +716,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Tests/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Tests/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/test:release \
--tag oneuptime/test:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/test:release \
--tag ghcr.io/oneuptime/test:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
probe-ingest-docker-image-deploy:
needs: [generate-build-number]
@@ -736,17 +781,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./ProbeIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./ProbeIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/probe-ingest:release \
--tag oneuptime/probe-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/probe-ingest:release \
--tag ghcr.io/oneuptime/probe-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
server-monitor-ingest-docker-image-deploy:
@@ -797,17 +847,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./ServerMonitorIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./ServerMonitorIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/server-monitor-ingest:release \
--tag oneuptime/server-monitor-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/server-monitor-ingest:release \
--tag ghcr.io/oneuptime/server-monitor-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -859,17 +914,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./OpenTelemetryIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./OpenTelemetryIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/open-telemetry-ingest:release \
--tag oneuptime/open-telemetry-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/open-telemetry-ingest:release \
--tag ghcr.io/oneuptime/open-telemetry-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
incoming-request-ingest-docker-image-deploy:
@@ -920,17 +980,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./IncomingRequestIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./IncomingRequestIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/incoming-request-ingest:release \
--tag oneuptime/incoming-request-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/incoming-request-ingest:release \
--tag ghcr.io/oneuptime/incoming-request-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
fluent-ingest-docker-image-deploy:
needs: [generate-build-number]
@@ -980,17 +1045,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./FluentIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./FluentIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/fluent-ingest:release \
--tag oneuptime/fluent-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/fluent-ingest:release \
--tag ghcr.io/oneuptime/fluent-ingest:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
probe-docker-image-deploy:
needs: [generate-build-number]
@@ -1040,78 +1110,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Probe/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
haraka-docker-image-deploy:
needs: [generate-build-number]
runs-on: ubuntu-latest
steps:
- name: Docker Meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
oneuptime/haraka
ghcr.io/oneuptime/haraka
tags: |
type=raw,value=release,enable=true
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v4
with:
node-version: latest
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Generate Dockerfile from Dockerfile.tpl
run: npm run prerun
# Build and deploy haraka.
- name: Login to Docker Hub
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
file: ./Haraka/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Probe/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/probe:release \
--tag oneuptime/probe:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/probe:release \
--tag ghcr.io/oneuptime/probe:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
admin-dashboard-docker-image-deploy:
needs: [generate-build-number]
@@ -1161,17 +1175,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./AdminDashboard/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./AdminDashboard/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/admin-dashboard:release \
--tag oneuptime/admin-dashboard:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/admin-dashboard:release \
--tag ghcr.io/oneuptime/admin-dashboard:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
dashboard-docker-image-deploy:
@@ -1222,17 +1241,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Dashboard/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Dashboard/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/dashboard:release \
--tag oneuptime/dashboard:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/dashboard:release \
--tag ghcr.io/oneuptime/dashboard:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
app-docker-image-deploy:
needs: [generate-build-number]
@@ -1282,17 +1306,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./App/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./App/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/app:release \
--tag oneuptime/app:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/app:release \
--tag ghcr.io/oneuptime/app:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
copilot-docker-image-deploy:
@@ -1343,17 +1372,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Copilot/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Copilot/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/copilot:release \
--tag oneuptime/copilot:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/copilot:release \
--tag ghcr.io/oneuptime/copilot:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
accounts-docker-image-deploy:
needs: [generate-build-number]
@@ -1403,17 +1437,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Accounts/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Accounts/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/accounts:release \
--tag oneuptime/accounts:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/accounts:release \
--tag ghcr.io/oneuptime/accounts:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
publish-npm-packages:
@@ -1503,17 +1542,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./LLM/Dockerfile
context: ./LLM
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./LLM/Dockerfile \
--platform linux/amd64 \
--push \
--tag oneuptime/llm:release \
--tag oneuptime/llm:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/llm:release \
--tag ghcr.io/oneuptime/llm:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
./LLM
docs-docker-image-deploy:
needs: generate-build-number
@@ -1565,17 +1609,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Docs/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Docs/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/docs:release \
--tag oneuptime/docs:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/docs:release \
--tag ghcr.io/oneuptime/docs:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -1630,17 +1679,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Worker/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Worker/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/worker:release \
--tag oneuptime/worker:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/worker:release \
--tag ghcr.io/oneuptime/worker:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -1695,17 +1749,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Workflow/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./Workflow/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/workflow:release \
--tag oneuptime/workflow:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/workflow:release \
--tag ghcr.io/oneuptime/workflow:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -1821,24 +1880,29 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./APIReference/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 45
max_attempts: 3
command: |
docker buildx build \
--file ./APIReference/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/api-reference:release \
--tag oneuptime/api-reference:7.0.${{needs.generate-build-number.outputs.build_number}} \
--tag ghcr.io/oneuptime/api-reference:release \
--tag ghcr.io/oneuptime/api-reference:7.0.${{needs.generate-build-number.outputs.build_number}} \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
test-e2e-release-saas:
runs-on: ubuntu-latest
needs: [open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, fluent-ingest-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, probe-ingest-docker-image-deploy, server-monitor-ingest-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy, incoming-request-ingest-docker-image-deploy]
needs: [open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, fluent-ingest-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, probe-ingest-docker-image-deploy, server-monitor-ingest-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy, incoming-request-ingest-docker-image-deploy]
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:
@@ -1891,7 +1955,7 @@ jobs:
test-e2e-release-self-hosted:
runs-on: ubuntu-latest
# After all the jobs runs
needs: [open-telemetry-ingest-docker-image-deploy, publish-mcp-server, copilot-docker-image-deploy, incoming-request-ingest-docker-image-deploy, fluent-ingest-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, probe-ingest-docker-image-deploy, server-monitor-ingest-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
needs: [open-telemetry-ingest-docker-image-deploy, publish-mcp-server, copilot-docker-image-deploy, incoming-request-ingest-docker-image-deploy, fluent-ingest-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, probe-ingest-docker-image-deploy, server-monitor-ingest-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:
@@ -1958,12 +2022,49 @@ jobs:
configuration: "./Scripts/Release/ChangelogConfig.json"
- run: echo "Changelog:"
- run: echo "${{steps.build_changelog.outputs.changelog}}"
- name: Fallback to commit messages if changelog empty
id: fallback_changelog
shell: bash
run: |
set -euo pipefail
CHANGELOG_CONTENT="${{steps.build_changelog.outputs.changelog}}"
OLD_PLACEHOLDER="No significant changes were made. We have just fixed minor bugs for this release. You can find the detailed information in the commit history."
NEW_PLACEHOLDER="(auto) No categorized pull requests. Fallback will list raw commit messages."
if echo "$CHANGELOG_CONTENT" | grep -Fq "$OLD_PLACEHOLDER" || echo "$CHANGELOG_CONTENT" | grep -Fq "$NEW_PLACEHOLDER"; then
echo "Detected empty placeholder changelog. Building commit list fallback."
# Find previous tag (skip the most recent tag which might be for an older release). If none, include all commits.
if prev_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --skip=1 --max-count=1) 2>/dev/null); then
echo "Previous tag: $prev_tag"
commits=$(git log --pretty=format:'- %s (%h)' "$prev_tag"..HEAD)
else
echo "No previous tag found; using full commit history on this branch."
commits=$(git log --pretty=format:'- %s (%h)')
fi
# If still empty (e.g., no commits), keep placeholder to avoid empty body.
if [ -z "$commits" ]; then
commits="(no commits found)"
fi
{
echo "changelog<<EOF"
echo "## Commit Messages"
echo ""
echo "$commits"
echo "EOF"
} >> "$GITHUB_OUTPUT"
else
# Pass through original changelog
{
echo "changelog<<EOF"
echo "$CHANGELOG_CONTENT"
echo "EOF"
} >> "$GITHUB_OUTPUT"
fi
- uses: ncipollo/release-action@v1
with:
tag: "7.0.${{needs.generate-build-number.outputs.build_number}}"
artifactErrorsFailBuild: true
body: |
${{steps.build_changelog.outputs.changelog}}
${{steps.fallback_changelog.outputs.changelog}}
infrastructure-agent-deploy:

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

View File

@@ -144,6 +144,7 @@ jobs:
- name: Install dependencies and build
run: |
cd MCP
npm update @oneuptime/common
npm install
npm run build
@@ -175,18 +176,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker images (test)
run: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file ./MCP/Dockerfile.tpl \
--tag oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag oneuptime/mcp-server:test \
--tag ghcr.io/oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag ghcr.io/oneuptime/mcp-server:test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=${{ steps.version.outputs.version }} \
--push .
echo "✅ Pushed test Docker images to Docker Hub and GitHub Container Registry"
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file ./MCP/Dockerfile.tpl \
--tag oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag oneuptime/mcp-server:test \
--tag ghcr.io/oneuptime/mcp-server:${{ steps.version.outputs.version }} \
--tag ghcr.io/oneuptime/mcp-server:test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=${{ steps.version.outputs.version }} \
--push .
echo "✅ Pushed test Docker images to Docker Hub and GitHub Container Registry"
- name: Upload MCP server artifact
uses: actions/upload-artifact@v4
@@ -268,18 +273,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./LLM/Dockerfile
context: ./LLM
# arm64 is not supported by the base image of the LLM
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./LLM/Dockerfile \
--platform linux/amd64 \
--push \
--tag oneuptime/llm:test \
--tag oneuptime/llm:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/llm:test \
--tag ghcr.io/oneuptime/llm:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
./LLM
nginx-docker-image-deploy:
@@ -331,17 +340,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Nginx/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Nginx/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/nginx:test \
--tag oneuptime/nginx:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/nginx:test \
--tag ghcr.io/oneuptime/nginx:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
e2e-docker-image-deploy:
@@ -393,17 +407,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./E2E/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./E2E/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/e2e:test \
--tag oneuptime/e2e:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/e2e:test \
--tag ghcr.io/oneuptime/e2e:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
test-server-docker-image-deploy:
needs: generate-build-number
@@ -454,17 +473,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./TestServer/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./TestServer/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/test-server:test \
--tag oneuptime/test-server:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/test-server:test \
--tag ghcr.io/oneuptime/test-server:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
otel-collector-docker-image-deploy:
needs: generate-build-number
@@ -515,17 +539,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./OTelCollector/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./OTelCollector/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/otel-collector:test \
--tag oneuptime/otel-collector:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/otel-collector:test \
--tag ghcr.io/oneuptime/otel-collector:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
isolated-vm-docker-image-deploy:
needs: generate-build-number
@@ -576,17 +605,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./IsolatedVM/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./IsolatedVM/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/isolated-vm:test \
--tag oneuptime/isolated-vm:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/isolated-vm:test \
--tag ghcr.io/oneuptime/isolated-vm:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
home-docker-image-deploy:
needs: generate-build-number
@@ -637,17 +671,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Home/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Home/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/home:test \
--tag oneuptime/home:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/home:test \
--tag ghcr.io/oneuptime/home:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -700,17 +739,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./StatusPage/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./StatusPage/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/status-page:test \
--tag oneuptime/status-page:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/status-page:test \
--tag ghcr.io/oneuptime/status-page:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -763,17 +807,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Tests/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Tests/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/test:test \
--tag oneuptime/test:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/test:test \
--tag ghcr.io/oneuptime/test:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
probe-ingest-docker-image-deploy:
needs: generate-build-number
@@ -824,17 +873,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./ProbeIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./ProbeIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/probe-ingest:test \
--tag oneuptime/probe-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/probe-ingest:test \
--tag ghcr.io/oneuptime/probe-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -887,17 +941,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./ServerMonitorIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./ServerMonitorIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/server-monitor-ingest:test \
--tag oneuptime/server-monitor-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/server-monitor-ingest:test \
--tag ghcr.io/oneuptime/server-monitor-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -951,17 +1010,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./IncomingRequestIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./IncomingRequestIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/incoming-request-ingest:test \
--tag oneuptime/incoming-request-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/incoming-request-ingest:test \
--tag ghcr.io/oneuptime/incoming-request-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
open-telemetry-ingest-docker-image-deploy:
needs: generate-build-number
@@ -1012,17 +1076,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./OpenTelemetryIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./OpenTelemetryIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/open-telemetry-ingest:test \
--tag oneuptime/open-telemetry-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/open-telemetry-ingest:test \
--tag ghcr.io/oneuptime/open-telemetry-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
fluent-ingest-docker-image-deploy:
needs: generate-build-number
@@ -1073,17 +1142,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./FluentIngest/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./FluentIngest/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/fluent-ingest:test \
--tag oneuptime/fluent-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/fluent-ingest:test \
--tag ghcr.io/oneuptime/fluent-ingest:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
probe-docker-image-deploy:
needs: generate-build-number
@@ -1134,78 +1208,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Probe/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
haraka-docker-image-deploy:
needs: generate-build-number
runs-on: ubuntu-latest
steps:
- name: Docker Meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
oneuptime/haraka
ghcr.io/oneuptime/haraka
tags: |
type=raw,value=test,enable=true
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v4
with:
node-version: latest
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Generate Dockerfile from Dockerfile.tpl
run: npm run prerun
# Build and deploy haraka.
- name: Login to Docker Hub
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
file: ./Haraka/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Probe/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/probe:test \
--tag oneuptime/probe:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/probe:test \
--tag ghcr.io/oneuptime/probe:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
dashboard-docker-image-deploy:
needs: generate-build-number
@@ -1256,17 +1274,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Dashboard/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Dashboard/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/dashboard:test \
--tag oneuptime/dashboard:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/dashboard:test \
--tag ghcr.io/oneuptime/dashboard:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
admin-dashboard-docker-image-deploy:
needs: generate-build-number
@@ -1317,17 +1340,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./AdminDashboard/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./AdminDashboard/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/admin-dashboard:test \
--tag oneuptime/admin-dashboard:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/admin-dashboard:test \
--tag ghcr.io/oneuptime/admin-dashboard:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
app-docker-image-deploy:
needs: generate-build-number
@@ -1378,17 +1406,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./App/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./App/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/app:test \
--tag oneuptime/app:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/app:test \
--tag ghcr.io/oneuptime/app:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -1442,17 +1475,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./APIReference/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./APIReference/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/api-reference:test \
--tag oneuptime/api-reference:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/api-reference:test \
--tag ghcr.io/oneuptime/api-reference:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
@@ -1505,17 +1543,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Accounts/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Accounts/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/accounts:test \
--tag oneuptime/accounts:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/accounts:test \
--tag ghcr.io/oneuptime/accounts:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
worker-docker-image-deploy:
needs: generate-build-number
@@ -1566,17 +1609,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Worker/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.copilot-docker-image-deploybuild_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Worker/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/worker:test \
--tag oneuptime/worker:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/worker:test \
--tag ghcr.io/oneuptime/worker:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
copilot-docker-image-deploy:
needs: generate-build-number
@@ -1627,17 +1675,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Copilot/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Copilot/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/copilot:test \
--tag oneuptime/copilot:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/copilot:test \
--tag ghcr.io/oneuptime/copilot:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
workflow-docker-image-deploy:
@@ -1689,17 +1742,22 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Workflow/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Workflow/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/workflow:test \
--tag oneuptime/workflow:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/workflow:test \
--tag ghcr.io/oneuptime/workflow:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
docs-docker-image-deploy:
@@ -1751,24 +1809,29 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: nick-fields/retry@v3
with:
file: ./Docs/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
timeout_minutes: 30
max_attempts: 3
command: |
docker buildx build \
--file ./Docs/Dockerfile \
--platform linux/amd64,linux/arm64 \
--push \
--tag oneuptime/docs:test \
--tag oneuptime/docs:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--tag ghcr.io/oneuptime/docs:test \
--tag ghcr.io/oneuptime/docs:7.0.${{needs.generate-build-number.outputs.build_number}}-test \
--build-arg GIT_SHA=${{ github.sha }} \
--build-arg APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}} \
.
test-helm-chart:
runs-on: ubuntu-latest
needs: [infrastructure-agent-deploy, publish-mcp-server, llm-docker-image-deploy, publish-terraform-provider, open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, docs-docker-image-deploy, worker-docker-image-deploy, workflow-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, api-reference-docker-image-deploy, test-server-docker-image-deploy, test-docker-image-deploy, probe-ingest-docker-image-deploy, server-monitor-ingest-docker-image-deploy, probe-docker-image-deploy, haraka-docker-image-deploy, dashboard-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, accounts-docker-image-deploy, otel-collector-docker-image-deploy, status-page-docker-image-deploy, nginx-docker-image-deploy, e2e-docker-image-deploy, fluent-ingest-docker-image-deploy, incoming-request-ingest-docker-image-deploy]
needs: [infrastructure-agent-deploy, publish-mcp-server, llm-docker-image-deploy, publish-terraform-provider, open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, docs-docker-image-deploy, worker-docker-image-deploy, workflow-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, api-reference-docker-image-deploy, test-server-docker-image-deploy, test-docker-image-deploy, probe-ingest-docker-image-deploy, server-monitor-ingest-docker-image-deploy, probe-docker-image-deploy, dashboard-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, accounts-docker-image-deploy, otel-collector-docker-image-deploy, status-page-docker-image-deploy, nginx-docker-image-deploy, e2e-docker-image-deploy, fluent-ingest-docker-image-deploy, incoming-request-ingest-docker-image-deploy]
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:

5
.gitignore vendored
View File

@@ -86,9 +86,6 @@ Backups/*.tar
.env
Haraka/dkim/keys/private_base64.txt
Haraka/dkim/keys/public_base64.txt
.eslintcache
HelmChart/Values/*.values.yaml
@@ -129,3 +126,5 @@ terraform-provider-example/**
MCP/build/
MCP/.env
MCP/node_modules
Dashboard/public/sw.js
.claude/settings.local.json

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

@@ -55,6 +55,7 @@
"@types/react-highlight": "^0.12.8",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^8.3.4",
"@types/web-push": "^3.6.4",
"acme-client": "^5.3.0",
"airtable": "^0.12.2",
"axios": "^1.7.2",
@@ -74,7 +75,6 @@
"json5": "^2.2.3",
"jsonwebtoken": "^9.0.0",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"marked": "^12.0.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
@@ -118,6 +118,7 @@
"universal-cookie": "^7.2.1",
"use-async-effect": "^2.2.6",
"uuid": "^8.3.2",
"web-push": "^3.6.7",
"zod": "^3.25.30"
},
"devDependencies": {
@@ -132,7 +133,6 @@
"@types/jest": "^28.1.4",
"@types/json2csv": "^5.0.3",
"@types/jsonwebtoken": "^8.5.9",
"@types/lodash": "^4.14.202",
"@types/node": "^17.0.45",
"@types/node-cron": "^3.0.7",
"@types/nodemailer": "^6.4.7",

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

@@ -59,6 +59,7 @@
"@types/react-highlight": "^0.12.8",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^8.3.4",
"@types/web-push": "^3.6.4",
"acme-client": "^5.3.0",
"airtable": "^0.12.2",
"axios": "^1.7.2",
@@ -78,7 +79,6 @@
"json5": "^2.2.3",
"jsonwebtoken": "^9.0.0",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"marked": "^12.0.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
@@ -122,6 +122,7 @@
"universal-cookie": "^7.2.1",
"use-async-effect": "^2.2.6",
"uuid": "^8.3.2",
"web-push": "^3.6.7",
"zod": "^3.25.30"
},
"devDependencies": {
@@ -136,7 +137,6 @@
"@types/jest": "^28.1.4",
"@types/json2csv": "^5.0.3",
"@types/jsonwebtoken": "^8.5.9",
"@types/lodash": "^4.14.202",
"@types/node": "^17.0.45",
"@types/node-cron": "^3.0.7",
"@types/nodemailer": "^6.4.7",

View File

@@ -58,6 +58,7 @@
"@types/react-highlight": "^0.12.8",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^8.3.4",
"@types/web-push": "^3.6.4",
"acme-client": "^5.3.0",
"airtable": "^0.12.2",
"axios": "^1.7.2",
@@ -77,7 +78,6 @@
"json5": "^2.2.3",
"jsonwebtoken": "^9.0.0",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"marked": "^12.0.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
@@ -121,6 +121,7 @@
"universal-cookie": "^7.2.1",
"use-async-effect": "^2.2.6",
"uuid": "^8.3.2",
"web-push": "^3.6.7",
"zod": "^3.25.30"
},
"devDependencies": {
@@ -135,7 +136,6 @@
"@types/jest": "^28.1.4",
"@types/json2csv": "^5.0.3",
"@types/jsonwebtoken": "^8.5.9",
"@types/lodash": "^4.14.202",
"@types/node": "^17.0.45",
"@types/node-cron": "^3.0.7",
"@types/nodemailer": "^6.4.7",

View File

@@ -21,7 +21,7 @@ import React, { FunctionComponent, ReactElement, useEffect } from "react";
const Settings: FunctionComponent = (): ReactElement => {
const [emailServerType, setemailServerType] = React.useState<EmailServerType>(
EmailServerType.Internal,
EmailServerType.CustomSMTP,
);
const [isLoading, setIsLoading] = React.useState<boolean>(true);
@@ -43,7 +43,7 @@ const Settings: FunctionComponent = (): ReactElement => {
if (globalConfig) {
setemailServerType(
globalConfig.emailServerType || EmailServerType.Internal,
globalConfig.emailServerType || EmailServerType.CustomSMTP,
);
}
@@ -127,7 +127,7 @@ const Settings: FunctionComponent = (): ReactElement => {
/>
<CardModelDetail
name="Internal SMTP Settings"
name="Email Server Settings"
cardProps={{
title: "Email Server Settings",
description:
@@ -172,7 +172,7 @@ const Settings: FunctionComponent = (): ReactElement => {
cardProps={{
title: "Custom Email and SMTP Settings",
description:
"If you have not enabled Internal SMTP server to send emails. Please configure your SMTP server here.",
"Please configure your SMTP server here to send emails.",
}}
isEditable={true}
editButtonText="Edit SMTP Config"

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,723 @@
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,
logSCIMOperation,
} 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 {
logSCIMOperation(
"ServiceProviderConfig",
"project",
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 {
logSCIMOperation("Users list", "project", 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;
logSCIMOperation(
"Users list",
"project",
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]!;
logSCIMOperation(
"Users list",
"project",
req.params["projectScimId"]!,
`filter by email: ${email}`,
);
if (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;
logSCIMOperation(
"Users list",
"project",
req.params["projectScimId"]!,
`found user with id: ${user.id}`,
);
} else {
logSCIMOperation(
"Users list",
"project",
req.params["projectScimId"]!,
`user not found for email: ${email}`,
);
return Response.sendJsonObjectResponse(
req,
res,
generateUsersListResponse([], startIndex, 0),
);
}
}
}
}
logSCIMOperation(
"Users list",
"project",
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,536 @@
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,
logSCIMOperation,
} 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 {
logSCIMOperation(
"ServiceProviderConfig",
"status-page",
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,
);
logger.debug(
`Status Page SCIM Users - statusPageId: ${statusPageId}, startIndex: ${startIndex}, count: ${count}`,
);
// Get all private users for this status page
const statusPageUsers: Array<StatusPagePrivateUser> =
await StatusPagePrivateUserService.findBy({
query: {
statusPageId: statusPageId,
},
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,264 @@
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 };
};
/**
* Log SCIM operation with consistent format
*/
export const logSCIMOperation: (
operation: string,
scimType: "project" | "status-page",
scimId: string,
details?: string,
) => void = (
operation: string,
scimType: "project" | "status-page",
scimId: string,
details?: string,
): void => {
const logPrefix: string =
scimType === "project" ? "Project SCIM" : "Status Page SCIM";
const message: string = `${logPrefix} ${operation} - scimId: ${scimId}${details ? `, ${details}` : ""}`;
logger.debug(message);
};

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

@@ -1,10 +1,8 @@
import Hostname from "Common/Types/API/Hostname";
import TwilioConfig from "Common/Types/CallAndSMS/TwilioConfig";
import Email from "Common/Types/Email";
import EmailServer from "Common/Types/Email/EmailServer";
import BadDataException from "Common/Types/Exception/BadDataException";
import ObjectID from "Common/Types/ObjectID";
import Port from "Common/Types/Port";
import { AdminDashboardClientURL } from "Common/Server/EnvironmentConfig";
import GlobalConfigService from "Common/Server/Services/GlobalConfigService";
import GlobalConfig, {
@@ -12,24 +10,6 @@ import GlobalConfig, {
} from "Common/Models/DatabaseModels/GlobalConfig";
import Phone from "Common/Types/Phone";
export const InternalSmtpPassword: string =
process.env["INTERNAL_SMTP_PASSWORD"] || "";
export const InternalSmtpHost: Hostname = new Hostname(
process.env["INTERNAL_SMTP_HOST"] || "haraka",
);
export const InternalSmtpPort: Port = new Port(2525);
export const InternalSmtpSecure: boolean = false;
export const InternalSmtpEmail: Email = new Email(
process.env["INTERNAL_SMTP_EMAIL"] || "noreply@oneuptime.com",
);
export const InternalSmtpFromName: string =
process.env["INTERNAL_SMTP_FROM_NAME"] || "OneUptime";
type GetGlobalSMTPConfig = () => Promise<EmailServer | null>;
export const getGlobalSMTPConfig: GetGlobalSMTPConfig =
@@ -132,10 +112,10 @@ export const getEmailServerType: GetEmailServerTypeFunction =
});
if (!globalConfig) {
return EmailServerType.Internal;
return EmailServerType.CustomSMTP;
}
return globalConfig.emailServerType || EmailServerType.Internal;
return globalConfig.emailServerType || EmailServerType.CustomSMTP;
};
export interface SendGridConfig {

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

@@ -1,10 +1,4 @@
import {
InternalSmtpEmail,
InternalSmtpFromName,
InternalSmtpHost,
InternalSmtpPassword,
InternalSmtpPort,
InternalSmtpSecure,
SendGridConfig,
getEmailServerType,
getGlobalSMTPConfig,
@@ -202,19 +196,6 @@ export default class MailService {
};
}
public static getInternalEmailServer(): EmailServer {
return {
id: undefined,
username: InternalSmtpEmail.toString(),
password: InternalSmtpPassword,
host: InternalSmtpHost,
port: InternalSmtpPort,
fromEmail: InternalSmtpEmail,
fromName: InternalSmtpFromName,
secure: InternalSmtpSecure,
};
}
public static async getGlobalFromEmail(): Promise<Email> {
const emailServer: EmailServer | null = await this.getGlobalSmtpSettings();
@@ -364,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> {
@@ -378,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.
@@ -540,17 +575,6 @@ export default class MailService {
options.emailServer = globalEmailServer;
}
if (
emailServerType === EmailServerType.Internal &&
(!options || !options.emailServer)
) {
if (!options) {
options = {};
}
options.emailServer = this.getInternalEmailServer();
}
if (options && options.emailServer && emailLog) {
emailLog.fromEmail = options.emailServer.fromEmail;
}

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"
}

4
App/package-lock.json generated
View File

@@ -65,6 +65,7 @@
"@types/react-highlight": "^0.12.8",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^8.3.4",
"@types/web-push": "^3.6.4",
"acme-client": "^5.3.0",
"airtable": "^0.12.2",
"axios": "^1.7.2",
@@ -84,7 +85,6 @@
"json5": "^2.2.3",
"jsonwebtoken": "^9.0.0",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"marked": "^12.0.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
@@ -128,6 +128,7 @@
"universal-cookie": "^7.2.1",
"use-async-effect": "^2.2.6",
"uuid": "^8.3.2",
"web-push": "^3.6.7",
"zod": "^3.25.30"
},
"devDependencies": {
@@ -142,7 +143,6 @@
"@types/jest": "^28.1.4",
"@types/json2csv": "^5.0.3",
"@types/jsonwebtoken": "^8.5.9",
"@types/lodash": "^4.14.202",
"@types/node": "^17.0.45",
"@types/node-cron": "^3.0.7",
"@types/nodemailer": "^6.4.7",

View File

@@ -64,6 +64,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "AlertOwnerTeam",
})
@Index(["alertId", "teamId", "projectId"])
export default class AlertOwnerTeam extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -63,6 +63,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "AlertOwnerUser",
})
@Index(["alertId", "userId", "projectId"])
export default class AlertOwnerUser extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -76,6 +76,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "AlertSeverity",
})
@Index(["projectId", "order"])
export default class AlertSeverity extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -76,6 +76,10 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "AlertState",
})
@Index(["projectId", "isCreatedState"])
@Index(["projectId", "isResolvedState"])
@Index(["projectId", "isAcknowledgedState"])
@Index(["projectId", "order"])
export default class AlertState extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -60,6 +60,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "AlertStateTimeline",
})
@Index(["alertId", "startsAt"])
@TableMetadata({
tableName: "AlertStateTimeline",
singularName: "Alert State Timeline",

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

@@ -17,7 +17,6 @@ import Port from "../../Types/Port";
import { Column, Entity } from "typeorm";
export enum EmailServerType {
Internal = "Internal",
Sendgrid = "Sendgrid",
CustomSMTP = "Custom SMTP",
}
@@ -49,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,
@@ -339,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

@@ -64,6 +64,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "IncidentOwnerTeam",
})
@Index(["incidentId", "teamId", "projectId"])
export default class IncidentOwnerTeam extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -63,6 +63,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "IncidentOwnerUser",
})
@Index(["incidentId", "userId", "projectId"])
export default class IncidentOwnerUser extends BaseModel {
@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

@@ -76,6 +76,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "IncidentSeverity",
})
@Index(["projectId", "order"])
export default class IncidentSeverity extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -76,6 +76,9 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "IncidentState",
})
@Index(["projectId", "isCreatedState"])
@Index(["projectId", "isResolvedState"])
@Index(["projectId", "order"])
export default class IncidentState extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -19,11 +19,14 @@ 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()
@CanAccessIfCanReadOn("incident")
@TenantColumn("projectId")
@Index(["incidentId", "startsAt"]) // Composite index for efficient incident timeline queries
@Index(["incidentId", "projectId", "startsAt"]) // Alternative composite index including project
@TableAccessControl({
create: [
Permission.ProjectOwner,
@@ -60,6 +63,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "IncidentStateTimeline",
})
@Index(["incidentId", "startsAt"])
@TableMetadata({
tableName: "IncidentStateTimeline",
singularName: "Incident State Timeline",
@@ -388,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: [
@@ -432,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,
@@ -458,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

@@ -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

@@ -57,10 +57,10 @@ import TelemetryService from "./TelemetryService";
],
})
@EnableWorkflow({
create: true,
delete: true,
update: true,
read: true,
create: false,
delete: false,
update: false,
read: false,
})
@CrudApiEndpoint(new Route("/metric-type"))
@SlugifyColumn("name", "slug")

View File

@@ -72,6 +72,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "MonitorOwnerTeam",
})
@Index(["monitorId", "teamId", "projectId"])
export default class MonitorOwnerTeam extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -71,6 +71,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "MonitorOwnerUser",
})
@Index(["monitorId", "userId", "projectId"])
export default class MonitorOwnerUser extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -24,6 +24,8 @@ export type MonitorStepProbeResponse = Dictionary<ProbeMonitorResponse>;
@EnableDocumentation()
@TenantColumn("projectId")
@Index(["monitorId", "probeId"]) // Composite index for efficient monitor-probe relationship queries
@Index(["monitorId", "projectId"]) // Alternative index for monitor queries within project
@TableAccessControl({
create: [
Permission.ProjectOwner,

View File

@@ -76,6 +76,8 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "MonitorStatus",
})
@Index(["projectId", "isOperationalState"])
@Index(["projectId", "isOfflineState"])
export default class MonitorStatus extends BaseModel {
@ColumnAccessControl({
create: [
@@ -454,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

@@ -25,6 +25,8 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@EnableDocumentation()
@CanAccessIfCanReadOn("monitor")
@TenantColumn("projectId")
@Index(["monitorId", "projectId", "startsAt"]) // Composite index for efficient timeline queries
@Index(["monitorId", "startsAt"]) // Alternative index for monitor-specific timeline queries
@TableAccessControl({
create: [
Permission.ProjectOwner,
@@ -62,6 +64,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "MonitorStatusTimeline",
})
@Index(["monitorId", "startsAt"])
@TableMetadata({
tableName: "MonitorStatusTimeline",
singularName: "Monitor Status Event",

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

@@ -51,6 +51,9 @@ import Alert from "./Alert";
@Entity({
name: "OnCallDutyPolicyExecutionLogTimeline",
})
@Index(["onCallDutyPolicyExecutionLogId", "createdAt"])
@Index(["projectId", "createdAt"])
@Index(["alertSentToUserId", "projectId"])
@TableMetadata({
tableName: "OnCallDutyPolicyExecutionLogTimeline",
singularName: "On-Call Duty Execution Log Timeline",

View File

@@ -72,6 +72,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "OnCallDutyPolicyOwnerTeam",
})
@Index(["onCallDutyPolicyId", "teamId", "projectId"])
export default class OnCallDutyPolicyOwnerTeam extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -71,6 +71,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "OnCallDutyPolicyOwnerUser",
})
@Index(["onCallDutyPolicyId", "userId", "projectId"])
export default class OnCallDutyPolicyOwnerUser extends BaseModel {
@ColumnAccessControl({
create: [

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: [

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

@@ -64,6 +64,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "ScheduledMaintenanceOwnerTeam",
})
@Index(["scheduledMaintenanceId", "teamId", "projectId"])
export default class ScheduledMaintenanceOwnerTeam extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -63,6 +63,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "ScheduledMaintenanceOwnerUser",
})
@Index(["scheduledMaintenanceId", "userId", "projectId"])
export default class ScheduledMaintenanceOwnerUser extends BaseModel {
@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

@@ -76,6 +76,9 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "ScheduledMaintenanceState",
})
@Index(["projectId", "order"])
@Index(["projectId", "isOngoingState"])
@Index(["projectId", "isEndedState"])
export default class ScheduledMaintenanceState extends BaseModel {
@ColumnAccessControl({
create: [
@@ -420,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,
@@ -453,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,
@@ -486,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,
@@ -519,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()
@@ -59,6 +60,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "ScheduledMaintenanceStateTimeline",
})
@Index(["scheduledMaintenanceId", "startsAt"])
@TableMetadata({
tableName: "ScheduledMaintenanceStateTimeline",
icon: IconProp.List,
@@ -387,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

@@ -21,6 +21,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,
@@ -443,27 +444,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 +530,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 +539,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 +562,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

@@ -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

@@ -72,6 +72,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "StatusPageOwnerTeam",
})
@Index(["statusPageId", "teamId", "projectId"])
export default class StatusPageOwnerTeam extends BaseModel {
@ColumnAccessControl({
create: [

View File

@@ -71,6 +71,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "StatusPageOwnerUser",
})
@Index(["statusPageId", "userId", "projectId"])
export default class StatusPageOwnerUser extends BaseModel {
@ColumnAccessControl({
create: [

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

@@ -52,6 +52,9 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "UserOnCallLogTimeline",
})
@Index(["userId", "createdAt"])
@Index(["onCallDutyPolicyExecutionLogId", "status"])
@Index(["projectId", "status"])
@TableMetadata({
tableName: "UserOnCallLogTimeline",
singularName: "User On-Call Log Timeline",

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

@@ -0,0 +1,144 @@
#!/usr/bin/env node
/**
* Universal Service Worker Generator for OneUptime Services
*
* This script can be used by any OneUptime service to generate
* a service worker from a template with dynamic versioning.
*
* Usage:
* node generate-service-worker.js [template-path] [output-path]
*
* Example:
* node generate-service-worker.js sw.js.template public/sw.js
*/
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
// Default values
const DEFAULT_APP_VERSION = '1.0.0';
const DEFAULT_GIT_SHA = 'local';
/**
* Get app version from environment or package.json
*/
function getAppVersion(packageJsonPath) {
// First try environment variable (Docker build)
if (process.env.APP_VERSION) {
return process.env.APP_VERSION;
}
// Fallback to package.json version
try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
return packageJson.version || DEFAULT_APP_VERSION;
} catch (error) {
console.warn('Could not read package.json, using default version');
return DEFAULT_APP_VERSION;
}
}
/**
* Get git SHA from environment
*/
function getGitSha() {
// Try environment variable first (Docker build)
if (process.env.GIT_SHA) {
return process.env.GIT_SHA.substring(0, 8); // Short SHA
}
// Try to get from git command if available
try {
const { execSync } = require('child_process');
const gitSha = execSync('git rev-parse --short HEAD', { encoding: 'utf8' }).trim();
return gitSha;
} catch (error) {
// Fallback to timestamp-based hash for local development
const timestamp = Date.now().toString();
const hash = crypto.createHash('md5').update(timestamp).digest('hex');
return hash.substring(0, 8);
}
}
/**
* Generate service worker from template
*/
function generateServiceWorker(templatePath, outputPath, serviceName = 'OneUptime') {
// Check if template exists
if (!fs.existsSync(templatePath)) {
console.error('❌ Service worker template not found:', templatePath);
process.exit(1);
}
// Read template
const template = fs.readFileSync(templatePath, 'utf8');
// Get version information
const packageJsonPath = path.join(path.dirname(templatePath), 'package.json');
const appVersion = getAppVersion(packageJsonPath);
const gitSha = getGitSha();
const buildTimestamp = new Date().toISOString();
console.log(`🔧 Generating service worker for ${serviceName}...`);
console.log(` App Version: ${appVersion}`);
console.log(` Git SHA: ${gitSha}`);
console.log(` Build Time: ${buildTimestamp}`);
// Replace placeholders
const generatedContent = template
.replace(/\{\{APP_VERSION\}\}/g, appVersion)
.replace(/\{\{GIT_SHA\}\}/g, gitSha)
.replace(/\{\{BUILD_TIMESTAMP\}\}/g, buildTimestamp)
.replace(/\{\{SERVICE_NAME\}\}/g, serviceName);
// Add generation comment at the top
const header = `/*
* Generated Service Worker for ${serviceName}
*
* Generated at: ${buildTimestamp}
* App Version: ${appVersion}
* Git SHA: ${gitSha}
*
* DO NOT EDIT THIS FILE DIRECTLY
* Edit the template file instead and run the generator script
*/
`;
const finalContent = header + generatedContent;
// Ensure output directory exists
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Write generated service worker
fs.writeFileSync(outputPath, finalContent, 'utf8');
console.log('✅ Service worker generated successfully:', outputPath);
console.log(` Cache version: oneuptime-v${appVersion}-${gitSha}`);
}
// Command line interface
if (require.main === module) {
const args = process.argv.slice(2);
const templatePath = args[0] || 'sw.js.template';
const outputPath = args[1] || 'public/sw.js';
const serviceName = args[2] || path.basename(process.cwd());
try {
// Resolve paths relative to current working directory
const resolvedTemplatePath = path.resolve(templatePath);
const resolvedOutputPath = path.resolve(outputPath);
generateServiceWorker(resolvedTemplatePath, resolvedOutputPath, serviceName);
} catch (error) {
console.error('❌ Failed to generate service worker:', error.message);
process.exit(1);
}
}
module.exports = { generateServiceWorker, getAppVersion, getGitSha };

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,
@@ -2146,6 +2147,7 @@ export default class StatusPageAPI extends BaseAPI<
projectId: true,
enableEmailSubscribers: true,
enableSlackSubscribers: true,
enableMicrosoftTeamsSubscribers: true,
enableSmsSubscribers: true,
allowSubscribersToChooseResources: true,
allowSubscribersToChooseEventTypes: true,
@@ -2357,6 +2359,7 @@ export default class StatusPageAPI extends BaseAPI<
statusPage.smtpConfig,
),
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
);
}
@@ -2372,6 +2375,7 @@ export default class StatusPageAPI extends BaseAPI<
customTwilioConfig: ProjectCallSMSConfigService.toTwilioConfig(
statusPage.callSmsConfig,
),
statusPageId: statusPage.id!,
}).catch((err: Error) => {
logger.error(err);
});
@@ -2417,6 +2421,7 @@ export default class StatusPageAPI extends BaseAPI<
enableEmailSubscribers: true,
enableSmsSubscribers: true,
enableSlackSubscribers: true,
enableMicrosoftTeamsSubscribers: true,
allowSubscribersToChooseResources: true,
allowSubscribersToChooseEventTypes: true,
showSubscriberPageOnStatusPage: true,
@@ -2478,15 +2483,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 +2528,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 +2598,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

@@ -1,14 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1753343522987 implements MigrationInterface {
public name = 'MigrationName1753343522987'
public name = "MigrationName1753343522987";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "UserPush" ALTER COLUMN "deviceToken" TYPE text`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "UserPush" ALTER COLUMN "deviceToken" TYPE character varying(500)`);
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "UserPush" ALTER COLUMN "deviceToken" TYPE text`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "UserPush" ALTER COLUMN "deviceToken" TYPE character varying(500)`,
);
}
}

View File

@@ -0,0 +1,47 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1753377161288 implements MigrationInterface {
public name = "MigrationName1753377161288";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE INDEX "IDX_16db786b562f1db40c93d463c7" ON "IncidentStateTimeline" ("incidentId", "projectId", "startsAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_410cf30b966f88c287d368aa48" ON "IncidentStateTimeline" ("incidentId", "startsAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_ac648c5f1961bc1d5ec1ba21bd" ON "MonitorProbe" ("monitorId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_bde10e600047b06718db90a636" ON "MonitorProbe" ("monitorId", "probeId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_570f164ca5b3559eb8555eb1b1" ON "MonitorStatusTimeline" ("monitorId", "startsAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_466d392af405ccf2e8b552eb0e" ON "MonitorStatusTimeline" ("monitorId", "projectId", "startsAt") `,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "public"."IDX_466d392af405ccf2e8b552eb0e"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_570f164ca5b3559eb8555eb1b1"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_bde10e600047b06718db90a636"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_ac648c5f1961bc1d5ec1ba21bd"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_410cf30b966f88c287d368aa48"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_16db786b562f1db40c93d463c7"`,
);
}
}

View File

@@ -0,0 +1,131 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddPerformanceIndexes1753378524062 implements MigrationInterface {
public name = "AddPerformanceIndexes1753378524062";
public async up(queryRunner: QueryRunner): Promise<void> {
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_3c2f8998deba67cedb958fc08f" ON "IncidentSeverity" ("projectId", "order") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_2283c2d1aab23419b784db0d84" ON "IncidentState" ("projectId", "order") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_4ed23cf5e6614ee930972ab6b5" ON "IncidentState" ("projectId", "isResolvedState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b231eb3cdc945e53947495cf76" ON "IncidentState" ("projectId", "isCreatedState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_5c9760b0f7df9fe68efd52151d" ON "MonitorStatus" ("projectId", "isOfflineState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_9c64d2b5df8c5cac0ece90d899" ON "MonitorStatus" ("projectId", "isOperationalState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_4490b10d3394a9be5f27f8fc3b" ON "IncidentOwnerTeam" ("incidentId", "teamId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_1d8d2229e31e4ec13ec99c79ae" ON "IncidentOwnerUser" ("incidentId", "userId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_7b7272644aab237d503ed3429a" ON "MonitorOwnerTeam" ("monitorId", "teamId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_6f6246149ab744fd62ada06ee5" ON "MonitorOwnerUser" ("monitorId", "userId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_c98e7e9e31d674cf5c47b15f36" ON "AlertSeverity" ("projectId", "order") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_3bb6dc217814170a3b37e21bf5" ON "AlertState" ("projectId", "order") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b20be7b2ca1a6dc602da305f8a" ON "AlertState" ("projectId", "isAcknowledgedState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_ae2854ea86740fdd56eaf2fea9" ON "AlertState" ("projectId", "isResolvedState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_91ad158d170a9b51a2046fcc87" ON "AlertState" ("projectId", "isCreatedState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_d640454e87b3dd4f24f9c527d2" ON "AlertStateTimeline" ("alertId", "startsAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_dfbcaebaa02d06a556fd2e155c" ON "AlertOwnerTeam" ("alertId", "teamId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_042a7841d65141fb940de9d881" ON "AlertOwnerUser" ("alertId", "userId", "projectId") `,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "public"."IDX_042a7841d65141fb940de9d881"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_dfbcaebaa02d06a556fd2e155c"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_d640454e87b3dd4f24f9c527d2"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_91ad158d170a9b51a2046fcc87"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_ae2854ea86740fdd56eaf2fea9"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b20be7b2ca1a6dc602da305f8a"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_3bb6dc217814170a3b37e21bf5"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c98e7e9e31d674cf5c47b15f36"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_6f6246149ab744fd62ada06ee5"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_7b7272644aab237d503ed3429a"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_1d8d2229e31e4ec13ec99c79ae"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_4490b10d3394a9be5f27f8fc3b"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_9c64d2b5df8c5cac0ece90d899"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_5c9760b0f7df9fe68efd52151d"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b231eb3cdc945e53947495cf76"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_4ed23cf5e6614ee930972ab6b5"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_2283c2d1aab23419b784db0d84"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_3c2f8998deba67cedb958fc08f"`,
);
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,119 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1753383711511 implements MigrationInterface {
public name = "MigrationName1753383711511";
public async up(queryRunner: QueryRunner): Promise<void> {
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_b03e14b5a5fc9f5b8603283c88" ON "OnCallDutyPolicyExecutionLogTimeline" ("alertSentToUserId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_114e3f761691867aa919ab6b6e" ON "OnCallDutyPolicyExecutionLogTimeline" ("projectId", "createdAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_f34e1244e487f705e7c6b25831" ON "OnCallDutyPolicyExecutionLogTimeline" ("onCallDutyPolicyExecutionLogId", "createdAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_34f21c8ae164fb90be806818a8" ON "OnCallDutyPolicyOwnerTeam" ("onCallDutyPolicyId", "teamId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_1539db4bbd6ada58abb940b058" ON "OnCallDutyPolicyOwnerUser" ("onCallDutyPolicyId", "userId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_00439dd14338c3ee4e81d0714a" ON "ScheduledMaintenanceState" ("projectId", "isEndedState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_7addde4d27f13be56651000df9" ON "ScheduledMaintenanceState" ("projectId", "isOngoingState") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_e84431ba010571147933477cff" ON "ScheduledMaintenanceState" ("projectId", "order") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_b737666365dbea2e4c914fc6d3" ON "ScheduledMaintenanceOwnerTeam" ("scheduledMaintenanceId", "teamId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a4621b7155a01292b92569549f" ON "ScheduledMaintenanceOwnerUser" ("scheduledMaintenanceId", "userId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_c4ac940ddb05242a166567edbb" ON "ScheduledMaintenanceStateTimeline" ("scheduledMaintenanceId", "startsAt") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_4873976169085f14bdc39e168d" ON "StatusPageOwnerTeam" ("statusPageId", "teamId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a9f80dc4f648f0957ce695dc61" ON "StatusPageOwnerUser" ("statusPageId", "userId", "projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_33ba145fe2826bb953e2ce9d3d" ON "UserOnCallLogTimeline" ("projectId", "status") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_90363cc35c22e377df8fdc5dfb" ON "UserOnCallLogTimeline" ("onCallDutyPolicyExecutionLogId", "status") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_89cccd6782b1ee84d20e9690d0" ON "UserOnCallLogTimeline" ("userId", "createdAt") `,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "public"."IDX_89cccd6782b1ee84d20e9690d0"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_90363cc35c22e377df8fdc5dfb"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_33ba145fe2826bb953e2ce9d3d"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a9f80dc4f648f0957ce695dc61"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_4873976169085f14bdc39e168d"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_c4ac940ddb05242a166567edbb"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a4621b7155a01292b92569549f"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b737666365dbea2e4c914fc6d3"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_e84431ba010571147933477cff"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_7addde4d27f13be56651000df9"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_00439dd14338c3ee4e81d0714a"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_1539db4bbd6ada58abb940b058"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_34f21c8ae164fb90be806818a8"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_f34e1244e487f705e7c6b25831"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_114e3f761691867aa919ab6b6e"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_b03e14b5a5fc9f5b8603283c88"`,
);
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,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"`,
);
}
}

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