Compare commits

..

5 Commits

445 changed files with 31498 additions and 30852 deletions

View File

@@ -209,6 +209,22 @@ jobs:
- 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 .
docker-build-probe:
runs-on: ubuntu-latest
env:

View File

@@ -70,7 +70,7 @@ jobs:
publish-mcp-server:
runs-on: ubuntu-latest
needs: [generate-build-number, publish-npm-packages]
needs: [generate-build-number]
env:
CI_PIPELINE_ID: ${{ github.run_number }}
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
@@ -138,7 +138,6 @@ jobs:
- name: Install dependencies
run: |
cd MCP
npm update @oneuptime/common
npm install
- name: Build MCP server
@@ -1053,6 +1052,67 @@ jobs:
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}}
admin-dashboard-docker-image-deploy:
needs: [generate-build-number]
runs-on: ubuntu-latest
@@ -1778,7 +1838,7 @@ jobs:
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, 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, 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]
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:
@@ -1831,7 +1891,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, 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, 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]
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:

View File

@@ -144,7 +144,6 @@ jobs:
- name: Install dependencies and build
run: |
cd MCP
npm update @oneuptime/common
npm install
npm run build
@@ -1147,6 +1146,67 @@ jobs:
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}}
dashboard-docker-image-deploy:
needs: generate-build-number
runs-on: ubuntu-latest
@@ -1708,7 +1768,7 @@ jobs:
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, 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, 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]
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:

5
.gitignore vendored
View File

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

View File

@@ -55,7 +55,6 @@
"@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",
@@ -75,6 +74,7 @@
"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,7 +118,6 @@
"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": {
@@ -133,6 +132,7 @@
"@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

@@ -59,7 +59,6 @@
"@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",
@@ -79,6 +78,7 @@
"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,7 +122,6 @@
"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": {
@@ -137,6 +136,7 @@
"@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,7 +58,6 @@
"@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,6 +77,7 @@
"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,7 +121,6 @@
"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,6 +135,7 @@
"@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.CustomSMTP,
EmailServerType.Internal,
);
const [isLoading, setIsLoading] = React.useState<boolean>(true);
@@ -43,7 +43,7 @@ const Settings: FunctionComponent = (): ReactElement => {
if (globalConfig) {
setemailServerType(
globalConfig.emailServerType || EmailServerType.CustomSMTP,
globalConfig.emailServerType || EmailServerType.Internal,
);
}
@@ -127,7 +127,7 @@ const Settings: FunctionComponent = (): ReactElement => {
/>
<CardModelDetail
name="Email Server Settings"
name="Internal SMTP Settings"
cardProps={{
title: "Email Server Settings",
description:
@@ -172,7 +172,7 @@ const Settings: FunctionComponent = (): ReactElement => {
cardProps={{
title: "Custom Email and SMTP Settings",
description:
"Please configure your SMTP server here to send emails.",
"If you have not enabled Internal SMTP server to send emails. Please configure your SMTP server here.",
}}
isEditable={true}
editButtonText="Edit SMTP Config"

View File

@@ -282,9 +282,6 @@ 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";
@@ -382,8 +379,6 @@ 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";
@@ -485,9 +480,6 @@ 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";
@@ -591,18 +583,6 @@ 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";
@@ -638,24 +618,6 @@ 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()}`,
@@ -1539,22 +1501,6 @@ 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

@@ -1,722 +0,0 @@
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 ProjectUser from "Common/Models/DatabaseModels/ProjectUser";
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,
},
});
} 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<ProjectUser> = {
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,7 +168,6 @@ router.post(
},
{
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
).catch((err: Error) => {
logger.error(err);
@@ -307,7 +306,6 @@ router.post(
},
{
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
).catch((err: Error) => {
logger.error(err);

View File

@@ -1,536 +0,0 @@
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,10 +1,8 @@
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";
@@ -21,10 +19,6 @@ 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

@@ -1,264 +0,0 @@
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

@@ -31,22 +31,6 @@ 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,43 +43,6 @@ 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

@@ -1,65 +0,0 @@
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,22 +30,6 @@ 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,8 +1,10 @@
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, {
@@ -10,6 +12,24 @@ 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 =
@@ -112,10 +132,10 @@ export const getEmailServerType: GetEmailServerTypeFunction =
});
if (!globalConfig) {
return EmailServerType.CustomSMTP;
return EmailServerType.Internal;
}
return globalConfig.emailServerType || EmailServerType.CustomSMTP;
return globalConfig.emailServerType || EmailServerType.Internal;
};
export interface SendGridConfig {

View File

@@ -2,7 +2,6 @@ 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";
@@ -16,7 +15,6 @@ 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,36 +28,6 @@ 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,
@@ -66,18 +36,6 @@ 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;
@@ -124,58 +82,14 @@ export default class CallService {
callLog.fromNumber = fromNumber;
callLog.callData =
options && options.isSensitive
? ({ message: "This call is sensitive and is not logged" } as any)
: ({
message: extractSayMessagesFromCallRequest(callRequest),
} as any);
? { message: "This call is sensitive and is not logged" }
: JSON.parse(JSON.stringify(callRequest));
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,4 +1,10 @@
import {
InternalSmtpEmail,
InternalSmtpFromName,
InternalSmtpHost,
InternalSmtpPassword,
InternalSmtpPort,
InternalSmtpSecure,
SendGridConfig,
getEmailServerType,
getGlobalSMTPConfig,
@@ -196,6 +202,19 @@ 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();
@@ -345,18 +364,6 @@ 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> {
@@ -371,48 +378,6 @@ 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.
@@ -575,6 +540,17 @@ 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

@@ -1,44 +0,0 @@
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,18 +31,6 @@ 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;
@@ -83,48 +71,6 @@ 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());

4
App/package-lock.json generated
View File

@@ -65,7 +65,6 @@
"@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",
@@ -85,6 +84,7 @@
"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,7 +128,6 @@
"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": {
@@ -143,6 +142,7 @@
"@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,7 +64,6 @@ 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,7 +63,6 @@ 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,7 +76,6 @@ 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,10 +76,6 @@ 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,7 +60,6 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "AlertStateTimeline",
})
@Index(["alertId", "startsAt"])
@TableMetadata({
tableName: "AlertStateTimeline",
singularName: "Alert State Timeline",

View File

@@ -1,14 +1,5 @@
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";
@@ -265,575 +256,6 @@ 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,7 +729,6 @@ export default class CopilotAction extends BaseModel {
type: TableColumnType.Boolean,
title: "Is Priority",
description: "Is Priority",
defaultValue: false,
})
@Column({
nullable: false,

View File

@@ -1,15 +1,6 @@
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";
@@ -298,576 +289,6 @@ 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,6 +17,7 @@ import Port from "../../Types/Port";
import { Column, Entity } from "typeorm";
export enum EmailServerType {
Internal = "Internal",
Sendgrid = "Sendgrid",
CustomSMTP = "Custom SMTP",
}
@@ -48,7 +49,6 @@ 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,7 +339,6 @@ 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,7 +27,6 @@ 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,
@@ -734,74 +733,29 @@ export default class Incident extends BaseModel {
public changeMonitorStatusToId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectIncident,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectIncident,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectIncident,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description:
"Status of notification sent to subscribers about this incident",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this incident?",
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotifiedOnIncidentCreated?: boolean = undefined;
@ColumnAccessControl({
create: [

View File

@@ -64,7 +64,6 @@ 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,7 +63,6 @@ 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,7 +17,6 @@ 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,73 +341,29 @@ export default class IncidentPublicNote extends BaseModel {
public note?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentPublicNote,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentPublicNote,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentPublicNote,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description: "Status of notification sent to subscribers about this note",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this note?",
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotifiedOnNoteCreated?: boolean = undefined;
@ColumnAccessControl({
create: [

View File

@@ -76,7 +76,6 @@ 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,9 +76,6 @@ 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,14 +19,11 @@ 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,
@@ -63,7 +60,6 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "IncidentStateTimeline",
})
@Index(["incidentId", "startsAt"])
@TableMetadata({
tableName: "IncidentStateTimeline",
singularName: "Incident State Timeline",
@@ -392,74 +388,29 @@ export default class IncidentStateTimeline extends BaseModel {
public incidentStateId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateIncidentStateTimeline,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadIncidentStateTimeline,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditIncidentStateTimeline,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description:
"Status of notification sent to subscribers about this incident state change",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this incident state change?",
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotified?: boolean = undefined;
@ColumnAccessControl({
create: [
@@ -481,7 +432,6 @@ 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,
@@ -508,7 +458,6 @@ 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,8 +100,6 @@ 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";
@@ -116,7 +114,6 @@ 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
@@ -182,7 +179,6 @@ 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;
@@ -280,7 +276,6 @@ const AllModelTypes: Array<{
ProjectSSO,
StatusPageSSO,
StatusPageSCIM,
MonitorProbe,
@@ -294,8 +289,6 @@ const AllModelTypes: Array<{
StatusPageOwnerUser,
SmsLog,
PushNotificationLog,
WorkspaceNotificationLog,
CallLog,
EmailLog,
@@ -387,8 +380,6 @@ const AllModelTypes: Array<{
MetricType,
OnCallDutyPolicyTimeLog,
ProjectSCIM,
];
const modelTypeMap: { [key: string]: { new (): BaseModel } } = {};

View File

@@ -72,7 +72,6 @@ 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,7 +71,6 @@ 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,8 +24,6 @@ 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,8 +76,6 @@ 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: [
@@ -456,7 +454,6 @@ 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,8 +25,6 @@ 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,
@@ -64,7 +62,6 @@ 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.Number,
type: TableColumnType.Boolean,
canReadOnRelationQuery: true,
title: "Repeat Policy Times If No One Acknowledges",
description:

View File

@@ -51,9 +51,6 @@ 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,7 +72,6 @@ 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,7 +71,6 @@ 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

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

View File

@@ -49,8 +49,8 @@ import {
})
@TableMetadata({
tableName: "ProjectUser",
singularName: "Project User",
pluralName: "Project Users",
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.",

View File

@@ -1,877 +0,0 @@
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,7 +269,6 @@ 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,7 +25,6 @@ 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,
@@ -716,74 +715,29 @@ export default class ScheduledMaintenance extends BaseModel {
public endsAt?: Date = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectScheduledMaintenance,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProjectScheduledMaintenance,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditProjectScheduledMaintenance,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status On Event Scheduled",
description:
"Status of notification sent to subscribers when event was scheduled",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
title: "Status Page Subscribers Notified On Event Scheduled",
description: "Status Page Subscribers Notified On Event Scheduled",
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotifiedOnEventScheduled?: boolean = undefined;
@ColumnAccessControl({
create: [

View File

@@ -64,7 +64,6 @@ 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,7 +63,6 @@ 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,7 +17,6 @@ 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()
@@ -343,73 +342,29 @@ export default class ScheduledMaintenancePublicNote extends BaseModel {
public note?: string = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateScheduledMaintenancePublicNote,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadScheduledMaintenancePublicNote,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditScheduledMaintenancePublicNote,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description: "Status of notification sent to subscribers about this note",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this note?",
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotifiedOnNoteCreated?: boolean = undefined;
@ColumnAccessControl({
create: [

View File

@@ -76,9 +76,6 @@ 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: [
@@ -423,7 +420,6 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Scheduled State",
description: "Is this state a scheduled state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -457,7 +453,6 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Ongoing State",
description: "Is this state a ongoing state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -491,7 +486,6 @@ export default class ScheduledMaintenanceState extends BaseModel {
canReadOnRelationQuery: true,
title: "Ended State",
description: "Is this state a ended state?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -525,7 +519,6 @@ 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,7 +18,6 @@ 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()
@@ -60,7 +59,6 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
@Entity({
name: "ScheduledMaintenanceStateTimeline",
})
@Index(["scheduledMaintenanceId", "startsAt"])
@TableMetadata({
tableName: "ScheduledMaintenanceStateTimeline",
icon: IconProp.List,
@@ -389,74 +387,29 @@ export default class ScheduledMaintenanceStateTimeline extends BaseModel {
public scheduledMaintenanceStateId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateScheduledMaintenanceStateTimeline,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadScheduledMaintenanceStateTimeline,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditScheduledMaintenanceStateTimeline,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
title: "Subscriber Notification Status",
description:
"Status of notification sent to subscribers about this scheduled maintenance state change",
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
title: "Are subscribers notified?",
description: "Are subscribers notified about this incident state change?",
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotified?: boolean = undefined;
@ColumnAccessControl({
create: [

View File

@@ -1,14 +1,5 @@
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";
@@ -265,575 +256,6 @@ 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

@@ -1438,12 +1438,7 @@ export default class StatusPage extends BaseModel {
public callSmsConfigId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateProjectStatusPage,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -1495,7 +1490,6 @@ 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)?",
@@ -1532,7 +1526,6 @@ 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)?",
@@ -1569,7 +1562,6 @@ 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)?",
@@ -1641,7 +1633,6 @@ 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,
@@ -1715,7 +1706,6 @@ 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.',
@@ -1798,7 +1788,6 @@ 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,
@@ -1942,7 +1931,6 @@ 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?",
})
@@ -1983,7 +1971,6 @@ 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,
@@ -2020,7 +2007,6 @@ 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({
@@ -2123,7 +2109,6 @@ 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,
@@ -2162,7 +2147,6 @@ 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,
@@ -2201,7 +2185,6 @@ 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,
@@ -2240,7 +2223,6 @@ 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,7 +21,6 @@ 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,
@@ -444,71 +443,27 @@ export default class StatusPageAnnouncement extends BaseModel {
public deletedByUserId?: ObjectID = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncement,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadStatusPageAnnouncement,
],
update: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.EditStatusPageAnnouncement,
],
update: [],
})
@TableColumn({
isDefaultValueColumn: true,
computed: true,
hideColumnInDocumentation: true,
type: TableColumnType.ShortText,
defaultValue: StatusPageSubscriberNotificationStatus.Pending,
type: TableColumnType.Boolean,
defaultValue: false,
})
@Column({
type: ColumnType.ShortText,
default: StatusPageSubscriberNotificationStatus.Pending,
type: ColumnType.Boolean,
default: false,
})
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;
public isStatusPageSubscribersNotified?: boolean = undefined;
@ColumnAccessControl({
create: [
@@ -530,7 +485,6 @@ 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,
@@ -539,12 +493,7 @@ export default class StatusPageAnnouncement extends BaseModel {
public shouldStatusPageSubscribersBeNotified?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageAnnouncement,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -562,7 +511,6 @@ 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,12 +474,7 @@ export default class StatusPageDomain extends BaseModel {
public isCnameVerified?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageDomain,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -494,7 +489,6 @@ export default class StatusPageDomain extends BaseModel {
type: TableColumnType.Boolean,
title: "SSL Ordered",
description: "Is SSL ordered?",
defaultValue: false,
})
@Column({
type: ColumnType.Boolean,
@@ -505,12 +499,7 @@ export default class StatusPageDomain extends BaseModel {
public isSslOrdered?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.CreateStatusPageDomain,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -525,7 +514,6 @@ 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,7 +72,6 @@ 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,7 +71,6 @@ 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

@@ -1,469 +0,0 @@
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

@@ -608,7 +608,6 @@ 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,
@@ -643,7 +642,6 @@ 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,
@@ -678,7 +676,6 @@ 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,7 +442,6 @@ export default class TableView extends BaseModel {
type: TableColumnType.Number,
canReadOnRelationQuery: true,
description: "Items on page",
defaultValue: 10,
})
@Column({
type: ColumnType.Number,

View File

@@ -146,11 +146,7 @@ export default class TelemetryUsageBilling extends BaseModel {
public productType?: ProductType = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ManageProjectBilling,
],
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
@@ -162,7 +158,6 @@ 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,11 +278,7 @@ class UserNotificationSetting extends BaseModel {
read: [Permission.CurrentUser],
update: [Permission.CurrentUser],
})
@TableColumn({
isDefaultValueColumn: true,
type: TableColumnType.Boolean,
defaultValue: false,
})
@TableColumn({ isDefaultValueColumn: true, type: TableColumnType.Boolean })
@Column({
type: ColumnType.Boolean,
default: false,

View File

@@ -52,9 +52,6 @@ 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

@@ -1,931 +0,0 @@
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

@@ -1,144 +0,0 @@
#!/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

@@ -2357,7 +2357,6 @@ export default class StatusPageAPI extends BaseAPI<
statusPage.smtpConfig,
),
projectId: statusPage.projectId!,
statusPageId: statusPage.id!,
},
);
}
@@ -2373,7 +2372,6 @@ export default class StatusPageAPI extends BaseAPI<
customTwilioConfig: ProjectCallSMSConfigService.toTwilioConfig(
statusPage.callSmsConfig,
),
statusPageId: statusPage.id!,
}).catch((err: Error) => {
logger.error(err);
});

View File

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

View File

@@ -4,7 +4,6 @@ import {
DashboardRoute,
AppApiRoute,
StatusPageApiRoute,
DocsRoute,
} from "../ServiceRoute";
import BillingConfig from "./BillingConfig";
import Protocol from "../Types/API/Protocol";
@@ -151,12 +150,6 @@ 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.
@@ -325,8 +318,6 @@ 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,17 +1,14 @@
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 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 down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "UserPush" ALTER COLUMN "deviceToken" TYPE character varying(500)`,
);
}
}

View File

@@ -1,47 +0,0 @@
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

@@ -1,131 +0,0 @@
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

@@ -1,119 +0,0 @@
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

@@ -1,67 +0,0 @@
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

@@ -1,17 +0,0 @@
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

@@ -1,63 +0,0 @@
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

@@ -1,150 +0,0 @@
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`,
);
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

@@ -1,259 +0,0 @@
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

@@ -1,105 +0,0 @@
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

@@ -1,105 +0,0 @@
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

@@ -1,101 +0,0 @@
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

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

View File

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

View File

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

View File

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

View File

@@ -143,21 +143,6 @@ import { MigrationName1752774923063 } from "./1752774923063-MigrationName";
import { MigrationName1753109689244 } from "./1753109689244-MigrationName";
import { AddEnableCustomSubscriberEmailNotificationFooterText1753131488925 } from "./1753131488925-AddEnableCustomSubscriberEmailNotificationFooterText";
import { MigrationName1753343522987 } from "./1753343522987-MigrationName";
import { MigrationName1753377161288 } from "./1753377161288-MigrationName";
import { AddPerformanceIndexes1753378524062 } from "./1753378524062-AddPerformanceIndexes";
import { MigrationName1753383711511 } from "./1753383711511-MigrationName";
import { MigrationName1754304193228 } from "./1754304193228-MigrationName";
import { MigrationName1754315774827 } from "./1754315774827-MigrationName";
import { MigrationName1754384418632 } from "./1754384418632-MigrationName";
import { MigrationName1754671483948 } from "./1754671483948-MigrationName";
import { MigrationName1754776130988 } from "./1754776130988-MigrationName";
import { MigrationName1754828812691 } from "./1754828812691-MigrationName";
import { MigrationName1754910440587 } from "./1754910440587-MigrationName";
import { MigrationName1755030730926 } from "./1755030730926-MigrationName";
import { MigrationName1755088852971 } from "./1755088852971-MigrationName";
import { MigrationName1755093133870 } from "./1755093133870-MigrationName";
import { MigrationName1755109893911 } from "./1755109893911-MigrationName";
import { MigrationName1755110936888 } from "./1755110936888-MigrationName";
export default [
InitialMigration,
@@ -304,20 +289,5 @@ export default [
MigrationName1752774923063,
MigrationName1753109689244,
AddEnableCustomSubscriberEmailNotificationFooterText1753131488925,
MigrationName1753343522987,
MigrationName1753377161288,
AddPerformanceIndexes1753378524062,
MigrationName1753383711511,
MigrationName1754304193228,
MigrationName1754315774827,
MigrationName1754384418632,
MigrationName1754671483948,
MigrationName1754776130988,
MigrationName1754828812691,
MigrationName1754910440587,
MigrationName1755030730926,
MigrationName1755088852971,
MigrationName1755093133870,
MigrationName1755109893911,
MigrationName1755110936888,
MigrationName1753343522987
];

View File

@@ -16,19 +16,15 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
export enum QueueName {
Workflow = "Workflow",
Worker = "Worker",
Telemetry = "Telemetry",
FluentIngest = "FluentIngest",
IncomingRequestIngest = "IncomingRequestIngest",
ServerMonitorIngest = "ServerMonitorIngest",
ProbeIngest = "ProbeIngest",
OtelIngestTraces = "OtelIngestTraces",
OtelIngestMetrics = "OtelIngestMetrics",
OtelIngestLogs = "OtelIngestLogs",
}
export type QueueJob = Job;
export default class Queue {
private static queueDict: Dictionary<BullQueue> = {};
// track queues we have already run initial cleanup on
private static cleanedQueueNames: Set<string> = new Set<string>();
@CaptureSpan()
public static getQueue(queueName: QueueName): BullQueue {
@@ -43,37 +39,11 @@ export default class Queue {
port: RedisPort.toNumber(),
password: RedisPassword,
},
// Keep BullMQ data under control to avoid Redis bloat
defaultJobOptions: {
// keep only recent completed/failed jobs
removeOnComplete: { count: 500 }, // keep last 1000 completed jobs
removeOnFail: { count: 100 }, // keep last 500 failed jobs
},
// Optionally cap the event stream length (supported in BullMQ >= v5)
// This helps prevent the :events stream from growing indefinitely
streams: {
events: { maxLen: 1000 },
},
});
// save it to the dictionary
this.queueDict[queueName] = queue;
// Fire-and-forget initial cleanup for legacy/old data if not done before
if (!this.cleanedQueueNames.has(queueName)) {
this.cleanedQueueNames.add(queueName);
// Clean jobs older than 1 days to reclaim memory from historic runs
const oneDaysMs: number = 1 * 24 * 60 * 60 * 1000;
void (async () => {
try {
await queue.clean(oneDaysMs, 1000, "completed");
await queue.clean(oneDaysMs, 1000, "failed");
} catch {
// ignore cleanup errors to not impact normal flow
}
})();
}
return queue;
}
@@ -166,97 +136,4 @@ export default class Queue {
return jobAdded;
}
@CaptureSpan()
public static async getQueueSize(queueName: QueueName): Promise<number> {
const queue: BullQueue = this.getQueue(queueName);
const waitingCount: number = await queue.getWaitingCount();
const activeCount: number = await queue.getActiveCount();
const delayedCount: number = await queue.getDelayedCount();
return waitingCount + activeCount + delayedCount;
}
@CaptureSpan()
public static async getQueueStats(queueName: QueueName): Promise<{
waiting: number;
active: number;
completed: number;
failed: number;
delayed: number;
total: number;
}> {
const queue: BullQueue = this.getQueue(queueName);
const waitingCount: number = await queue.getWaitingCount();
const activeCount: number = await queue.getActiveCount();
const completedCount: number = await queue.getCompletedCount();
const failedCount: number = await queue.getFailedCount();
const delayedCount: number = await queue.getDelayedCount();
return {
waiting: waitingCount,
active: activeCount,
completed: completedCount,
failed: failedCount,
delayed: delayedCount,
total:
waitingCount +
activeCount +
completedCount +
failedCount +
delayedCount,
};
}
@CaptureSpan()
public static async getFailedJobs(
queueName: QueueName,
options?: {
start?: number;
end?: number;
},
): Promise<
Array<{
id: string;
name: string;
data: JSONObject;
failedReason: string;
stackTrace?: string;
processedOn: Date | null;
finishedOn: Date | null;
attemptsMade: number;
}>
> {
const queue: BullQueue = this.getQueue(queueName);
const start: number = options?.start || 0;
const end: number = options?.end || 100;
const failed: Job[] = await queue.getFailed(start, end);
return failed.map((job: Job) => {
const result: {
id: string;
name: string;
data: JSONObject;
failedReason: string;
stackTrace?: string;
processedOn: Date | null;
finishedOn: Date | null;
attemptsMade: number;
} = {
id: job.id || "unknown",
name: job.name || "unknown",
data: job.data as JSONObject,
failedReason: job.failedReason || "No reason provided",
processedOn: job.processedOn ? new Date(job.processedOn) : null,
finishedOn: job.finishedOn ? new Date(job.finishedOn) : null,
attemptsMade: job.attemptsMade || 0,
};
if (job.stacktrace && job.stacktrace.length > 0) {
result.stackTrace = job.stacktrace.join("\n");
}
return result;
});
}
}

View File

@@ -38,9 +38,6 @@ export default class ClusterKeyAuthorization {
} else if (req.headers && req.headers["clusterkey"]) {
// Header keys are automatically transformed to lowercase
clusterKey = req.headers["clusterkey"] as string;
} else if (req.headers && req.headers["x-clusterkey"]) {
// KEDA TriggerAuthentication sends headers with X- prefix
clusterKey = req.headers["x-clusterkey"] as string;
} else if (req.body && req.body.clusterKey) {
clusterKey = req.body.clusterKey;
} else {

View File

@@ -1,127 +0,0 @@
import ProjectSCIMService from "../Services/ProjectSCIMService";
import StatusPageSCIMService from "../Services/StatusPageSCIMService";
import {
ExpressRequest,
ExpressResponse,
NextFunction,
OneUptimeRequest,
} from "../Utils/Express";
import ObjectID from "../../Types/ObjectID";
import ProjectSCIM from "../../Models/DatabaseModels/ProjectSCIM";
import StatusPageSCIM from "../../Models/DatabaseModels/StatusPageSCIM";
import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
import BadRequestException from "../../Types/Exception/BadRequestException";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import logger from "../Utils/Logger";
export default class SCIMMiddleware {
@CaptureSpan()
public static async isAuthorizedSCIMRequest(
req: ExpressRequest,
_res: ExpressResponse,
next: NextFunction,
): Promise<void> {
try {
const oneuptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
// Extract SCIM ID from URL path (could be project or status page)
const scimId: string | undefined =
req.params["projectScimId"] || req.params["statusPageScimId"];
if (!scimId) {
throw new BadRequestException("SCIM ID is required");
}
// Extract bearer token from Authorization header
let bearerToken: string | undefined;
if (req.headers?.["authorization"]) {
const authHeader: string = req.headers["authorization"] as string;
if (authHeader.startsWith("Bearer ")) {
bearerToken = authHeader.substring(7);
}
}
logger.debug(
`SCIM Authorization: scimId=${scimId}, bearerToken=${
bearerToken ? "***" : "missing"
}`,
);
if (!bearerToken) {
throw new NotAuthorizedException(
"Bearer token is required for SCIM authentication",
);
}
// Try to find Project SCIM configuration first
const projectScimConfig: ProjectSCIM | null =
await ProjectSCIMService.findOneBy({
query: {
_id: new ObjectID(scimId),
bearerToken: bearerToken,
},
select: {
_id: true,
projectId: true,
autoProvisionUsers: true,
autoDeprovisionUsers: true,
teams: {
_id: true,
name: true,
},
},
props: {
isRoot: true,
},
});
if (projectScimConfig) {
// Store Project SCIM configuration
oneuptimeRequest.bearerTokenData = {
scimConfig: projectScimConfig,
projectId: projectScimConfig.projectId,
projectScimId: new ObjectID(scimId),
type: "project-scim",
};
return next();
}
// If not found, try Status Page SCIM configuration
const statusPageScimConfig: StatusPageSCIM | null =
await StatusPageSCIMService.findOneBy({
query: {
_id: new ObjectID(scimId),
bearerToken: bearerToken,
},
select: {
_id: true,
projectId: true,
statusPageId: true,
autoProvisionUsers: true,
autoDeprovisionUsers: true,
},
props: {
isRoot: true,
},
});
if (statusPageScimConfig) {
// Store Status Page SCIM configuration
oneuptimeRequest.bearerTokenData = {
scimConfig: statusPageScimConfig,
projectId: statusPageScimConfig.projectId,
statusPageId: statusPageScimConfig.statusPageId,
statusPageScimId: new ObjectID(scimId),
type: "status-page-scim",
};
return next();
}
// If neither found, throw error
throw new NotAuthorizedException(
"Invalid bearer token or SCIM configuration not found",
);
} catch (err) {
return next(err);
}
}
}

View File

@@ -54,7 +54,6 @@ import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import MetricType from "../../Models/DatabaseModels/MetricType";
import Dictionary from "../../Types/Dictionary";
import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
export class Service extends DatabaseService<Model> {
public constructor() {
@@ -273,7 +272,6 @@ export class Service extends DatabaseService<Model> {
throw new BadDataException("currentAlertStateId is required");
}
// Get alert data for feed creation
const alert: Model | null = await this.findOneById({
id: createdItem.id,
select: {
@@ -306,258 +304,147 @@ export class Service extends DatabaseService<Model> {
throw new BadDataException("Alert not found");
}
// Execute core operations in parallel first
const coreOperations: Array<Promise<any>> = [];
const createdByUserId: ObjectID | undefined | null =
createdItem.createdByUserId || createdItem.createdByUser?.id;
// Create feed item asynchronously
coreOperations.push(this.createAlertFeedAsync(alert, createdItem));
// send message to workspaces - slack, teams, etc.
const workspaceResult: {
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
} | null =
await AlertWorkspaceMessages.createChannelsAndInviteUsersToChannels({
projectId: createdItem.projectId,
alertId: createdItem.id!,
alertNumber: createdItem.alertNumber!,
});
// Handle state change asynchronously
coreOperations.push(this.handleAlertStateChangeAsync(createdItem));
logger.debug("Alert created. Workspace result:");
logger.debug(workspaceResult);
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
// update alert with these channels.
await this.updateOneById({
id: createdItem.id!,
data: {
postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
},
props: {
isRoot: true,
},
});
}
let feedInfoInMarkdown: string = `#### 🚨 Alert ${createdItem.alertNumber?.toString()} Created:
**${createdItem.title || "No title provided."}**:
${createdItem.description || "No description provided."}
`;
if (alert.currentAlertState?.name) {
feedInfoInMarkdown += `🔴 **Alert State**: ${alert.currentAlertState.name} \n\n`;
}
if (alert.alertSeverity?.name) {
feedInfoInMarkdown += `⚠️ **Severity**: ${alert.alertSeverity.name} \n\n`;
}
if (alert.monitor) {
feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
const monitor: Monitor = alert.monitor;
feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
feedInfoInMarkdown += `\n\n`;
}
if (createdItem.rootCause) {
feedInfoInMarkdown += `\n
📄 **Root Cause**:
${createdItem.rootCause || "No root cause provided."}
`;
}
if (createdItem.remediationNotes) {
feedInfoInMarkdown += `\n
🎯 **Remediation Notes**:
${createdItem.remediationNotes || "No remediation notes provided."}
`;
}
const alertCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
await AlertWorkspaceMessages.getAlertCreateMessageBlocks({
alertId: createdItem.id!,
projectId: createdItem.projectId!,
});
await AlertFeedService.createAlertFeedItem({
alertId: createdItem.id!,
projectId: createdItem.projectId!,
alertFeedEventType: AlertFeedEventType.AlertCreated,
displayColor: Red500,
feedInfoInMarkdown: feedInfoInMarkdown,
userId: createdByUserId || undefined,
workspaceNotification: {
appendMessageBlocks: alertCreateMessageBlocks,
sendWorkspaceNotification: true,
},
});
await this.changeAlertState({
projectId: createdItem.projectId,
alertId: createdItem.id,
alertStateId: createdItem.currentAlertStateId,
notifyOwners: false,
rootCause: createdItem.rootCause,
stateChangeLog: createdItem.createdStateLog,
props: {
isRoot: true,
},
});
// add owners.
// Handle owner assignment asynchronously
if (
onCreate.createBy.miscDataProps &&
(onCreate.createBy.miscDataProps["ownerTeams"] ||
onCreate.createBy.miscDataProps["ownerUsers"])
) {
coreOperations.push(
this.addOwners(
createdItem.projectId,
createdItem.id,
(onCreate.createBy.miscDataProps["ownerUsers"] as Array<ObjectID>) ||
[],
(onCreate.createBy.miscDataProps["ownerTeams"] as Array<ObjectID>) ||
[],
false,
onCreate.createBy.props,
),
await this.addOwners(
createdItem.projectId,
createdItem.id,
(onCreate.createBy.miscDataProps["ownerUsers"] as Array<ObjectID>) ||
[],
(onCreate.createBy.miscDataProps["ownerTeams"] as Array<ObjectID>) ||
[],
false,
onCreate.createBy.props,
);
}
// Execute core operations in parallel with error handling
Promise.allSettled(coreOperations)
.then((coreResults: any[]) => {
// Log any errors from core operations
coreResults.forEach((result: any, index: number) => {
if (result.status === "rejected") {
logger.error(
`Core operation ${index} failed in AlertService.onCreateSuccess: ${result.reason}`,
);
}
});
// Handle on-call duty policies asynchronously
if (
createdItem.onCallDutyPolicies?.length &&
createdItem.onCallDutyPolicies?.length > 0
) {
this.executeAlertOnCallDutyPoliciesAsync(createdItem).catch(
(error: Error) => {
logger.error(
`On-call duty policy execution failed in AlertService.onCreateSuccess: ${error}`,
);
},
);
}
// Handle workspace operations after core operations complete
if (createdItem.projectId && createdItem.id) {
// Run workspace operations in background without blocking response
this.handleAlertWorkspaceOperationsAsync(createdItem).catch(
(error: Error) => {
logger.error(
`Workspace operations failed in AlertService.onCreateSuccess: ${error}`,
);
},
);
}
})
.catch((error: Error) => {
logger.error(
`Critical error in AlertService core operations: ${error}`,
if (
createdItem.onCallDutyPolicies?.length &&
createdItem.onCallDutyPolicies?.length > 0
) {
for (const policy of createdItem.onCallDutyPolicies) {
await OnCallDutyPolicyService.executePolicy(
new ObjectID(policy._id as string),
{
triggeredByAlertId: createdItem.id!,
userNotificationEventType: UserNotificationEventType.AlertCreated,
},
);
});
}
}
return createdItem;
}
@CaptureSpan()
private async handleAlertWorkspaceOperationsAsync(
createdItem: Model,
): Promise<void> {
try {
if (!createdItem.projectId || !createdItem.id) {
throw new BadDataException(
"projectId and id are required for workspace operations",
);
}
// send message to workspaces - slack, teams, etc.
const workspaceResult: {
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
} | null =
await AlertWorkspaceMessages.createChannelsAndInviteUsersToChannels({
projectId: createdItem.projectId,
alertId: createdItem.id,
alertNumber: createdItem.alertNumber!,
});
logger.debug("Alert created. Workspace result:");
logger.debug(workspaceResult);
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
// update alert with these channels.
await this.updateOneById({
id: createdItem.id,
data: {
postUpdatesToWorkspaceChannels:
workspaceResult.channelsCreated || [],
},
props: {
isRoot: true,
},
});
}
} catch (error) {
logger.error(`Error in handleAlertWorkspaceOperationsAsync: ${error}`);
throw error;
}
}
@CaptureSpan()
private async createAlertFeedAsync(
alert: Model,
createdItem: Model,
): Promise<void> {
try {
const createdByUserId: ObjectID | undefined | null =
createdItem.createdByUserId || createdItem.createdByUser?.id;
let feedInfoInMarkdown: string = `#### 🚨 Alert ${createdItem.alertNumber?.toString()} Created:
**${createdItem.title || "No title provided."}**:
${createdItem.description || "No description provided."}
`;
if (alert.currentAlertState?.name) {
feedInfoInMarkdown += `🔴 **Alert State**: ${alert.currentAlertState.name} \n\n`;
}
if (alert.alertSeverity?.name) {
feedInfoInMarkdown += `⚠️ **Severity**: ${alert.alertSeverity.name} \n\n`;
}
if (alert.monitor) {
feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
const monitor: Monitor = alert.monitor;
feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
feedInfoInMarkdown += `\n\n`;
}
if (createdItem.rootCause) {
feedInfoInMarkdown += `\n
📄 **Root Cause**:
${createdItem.rootCause || "No root cause provided."}
`;
}
if (createdItem.remediationNotes) {
feedInfoInMarkdown += `\n
🎯 **Remediation Notes**:
${createdItem.remediationNotes || "No remediation notes provided."}
`;
}
const alertCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
await AlertWorkspaceMessages.getAlertCreateMessageBlocks({
alertId: createdItem.id!,
projectId: createdItem.projectId!,
});
await AlertFeedService.createAlertFeedItem({
alertId: createdItem.id!,
projectId: createdItem.projectId!,
alertFeedEventType: AlertFeedEventType.AlertCreated,
displayColor: Red500,
feedInfoInMarkdown: feedInfoInMarkdown,
userId: createdByUserId || undefined,
workspaceNotification: {
appendMessageBlocks: alertCreateMessageBlocks,
sendWorkspaceNotification: true,
},
});
} catch (error) {
logger.error(`Error in createAlertFeedAsync: ${error}`);
throw error;
}
}
@CaptureSpan()
private async handleAlertStateChangeAsync(createdItem: Model): Promise<void> {
try {
if (!createdItem.projectId || !createdItem.id) {
throw new BadDataException(
"projectId and id are required for state change",
);
}
await this.changeAlertState({
projectId: createdItem.projectId,
alertId: createdItem.id,
alertStateId: createdItem.currentAlertStateId!,
notifyOwners: false,
rootCause: createdItem.rootCause,
stateChangeLog: createdItem.createdStateLog,
props: {
isRoot: true,
},
});
} catch (error) {
logger.error(`Error in handleAlertStateChangeAsync: ${error}`);
throw error;
}
}
@CaptureSpan()
private async executeAlertOnCallDutyPoliciesAsync(
createdItem: Model,
): Promise<void> {
try {
if (
createdItem.onCallDutyPolicies?.length &&
createdItem.onCallDutyPolicies?.length > 0
) {
// Execute all on-call policies in parallel
const policyPromises: Promise<void>[] =
createdItem.onCallDutyPolicies.map((policy: OnCallDutyPolicy) => {
return OnCallDutyPolicyService.executePolicy(
new ObjectID(policy["_id"] as string),
{
triggeredByAlertId: createdItem.id!,
userNotificationEventType:
UserNotificationEventType.AlertCreated,
},
);
});
await Promise.allSettled(policyPromises);
}
} catch (error) {
logger.error(`Error in executeAlertOnCallDutyPoliciesAsync: ${error}`);
throw error;
}
}
@CaptureSpan()
public async getWorkspaceChannelForAlert(data: {
alertId: ObjectID;

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