mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 08:42:13 +02:00
Compare commits
449 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba463f44b1 | ||
|
|
a36d0e4258 | ||
|
|
6a9a535365 | ||
|
|
1b5ba60703 | ||
|
|
5ac205ddc0 | ||
|
|
668830063f | ||
|
|
ed06cef3b1 | ||
|
|
6c8154d94b | ||
|
|
ee99f3f558 | ||
|
|
30c9b8ab90 | ||
|
|
db7e862a31 | ||
|
|
3b3a6f35f1 | ||
|
|
e3ccf48251 | ||
|
|
f01b6f1944 | ||
|
|
832e88f288 | ||
|
|
9ceb2d4fc4 | ||
|
|
3b0c9ddaeb | ||
|
|
c6df51aae3 | ||
|
|
606e8d8349 | ||
|
|
b0ba865ea2 | ||
|
|
d48f86970c | ||
|
|
44be11adbb | ||
|
|
e0965390b9 | ||
|
|
75a9763eb1 | ||
|
|
952865298c | ||
|
|
eb90e19d12 | ||
|
|
7f81ae4009 | ||
|
|
cd8f090a5e | ||
|
|
35f483c650 | ||
|
|
8238ce4c5d | ||
|
|
39ab39b024 | ||
|
|
7e3f911225 | ||
|
|
8a8f975369 | ||
|
|
bef9411dcc | ||
|
|
e861f4b53c | ||
|
|
757a66bafa | ||
|
|
217ec6bcfc | ||
|
|
dd4f518a79 | ||
|
|
c87e1513d9 | ||
|
|
b4e4eb7043 | ||
|
|
26a4ba606e | ||
|
|
88cf88d125 | ||
|
|
499dec5b95 | ||
|
|
9a107188aa | ||
|
|
6822dc4f3e | ||
|
|
6977aec52d | ||
|
|
c9a3c23302 | ||
|
|
066f055a74 | ||
|
|
1da7b9747f | ||
|
|
e29af13b73 | ||
|
|
3e4074ef4b | ||
|
|
0f8330d110 | ||
|
|
4cba9d6042 | ||
|
|
556283e7f7 | ||
|
|
696a3b5fee | ||
|
|
cdd2f241c7 | ||
|
|
2a9978b539 | ||
|
|
e1917f1fd7 | ||
|
|
cb547790cf | ||
|
|
c754101194 | ||
|
|
a1b772bda1 | ||
|
|
a0e4b6b5c7 | ||
|
|
02cb4474a3 | ||
|
|
2db09a3aba | ||
|
|
e09efd5917 | ||
|
|
b45a47e167 | ||
|
|
fab4be14dc | ||
|
|
b717f0e09e | ||
|
|
89fc67831c | ||
|
|
a504ac95d8 | ||
|
|
a4f2206c83 | ||
|
|
271535d89f | ||
|
|
13f0723405 | ||
|
|
2159332317 | ||
|
|
3757ecb104 | ||
|
|
a40986d51b | ||
|
|
d5aa9529fa | ||
|
|
edc7362fcd | ||
|
|
e9de7fae51 | ||
|
|
8877536c14 | ||
|
|
5f0be6298c | ||
|
|
3d533db7c0 | ||
|
|
46b14a4792 | ||
|
|
a0b203d9b8 | ||
|
|
b55b20a55f | ||
|
|
b91104e7bd | ||
|
|
478b4dc381 | ||
|
|
8d7c88d4d0 | ||
|
|
9c35c26558 | ||
|
|
16166a70f8 | ||
|
|
42b80bab3c | ||
|
|
2724f4eeed | ||
|
|
b6f67f8faa | ||
|
|
a0bfa75e55 | ||
|
|
1e0b19efd4 | ||
|
|
e83d63c07e | ||
|
|
7eb0b79d7b | ||
|
|
2156c8f5d5 | ||
|
|
9564e57208 | ||
|
|
2ba91d6ddf | ||
|
|
668c88db52 | ||
|
|
e4faa3c995 | ||
|
|
d86f3a0a33 | ||
|
|
4dda09b406 | ||
|
|
ef605f1248 | ||
|
|
632365da7f | ||
|
|
6ca3d003f7 | ||
|
|
889b6e00c4 | ||
|
|
dfa8591562 | ||
|
|
85d073f110 | ||
|
|
55f6faaa60 | ||
|
|
6939ee1f0d | ||
|
|
316ef6ff53 | ||
|
|
9fe2395796 | ||
|
|
7b2a31ef96 | ||
|
|
7971bb2abb | ||
|
|
5eacc2a18e | ||
|
|
70d18ba49e | ||
|
|
3c9628abdb | ||
|
|
9793d95b80 | ||
|
|
881b190fd8 | ||
|
|
e30565bce3 | ||
|
|
f9517412e5 | ||
|
|
ed6d2faa8d | ||
|
|
a1ce939ffc | ||
|
|
b34cd86f05 | ||
|
|
45e752cabf | ||
|
|
fa89f9d1a5 | ||
|
|
9db08a9347 | ||
|
|
24c4d37b2c | ||
|
|
1f866ee325 | ||
|
|
70a0087344 | ||
|
|
3dea55f035 | ||
|
|
f47a6e7c6b | ||
|
|
788e8363ef | ||
|
|
c9d1c95b38 | ||
|
|
b3a18d69cb | ||
|
|
3b9e982c35 | ||
|
|
b28a832ba7 | ||
|
|
38b96e86c3 | ||
|
|
dafcd001f7 | ||
|
|
7882897466 | ||
|
|
3e62082ac2 | ||
|
|
e8d790925b | ||
|
|
83061b1ca8 | ||
|
|
554f353990 | ||
|
|
d857de0406 | ||
|
|
e4d4bbb680 | ||
|
|
4e8631cec9 | ||
|
|
1f96504c34 | ||
|
|
c0153f0ecb | ||
|
|
42f8a90eeb | ||
|
|
090d68f4e1 | ||
|
|
dcd04ddaa1 | ||
|
|
906438c325 | ||
|
|
53ce3537e9 | ||
|
|
550d7f2621 | ||
|
|
b1707a28f8 | ||
|
|
3eb15af79c | ||
|
|
bddd932eb8 | ||
|
|
8a73a7c7ab | ||
|
|
a7b6f70ed4 | ||
|
|
3dea88a97b | ||
|
|
5728c1a18c | ||
|
|
7da678e82b | ||
|
|
7b7cbbe6b8 | ||
|
|
658b359c2c | ||
|
|
ff9f97f095 | ||
|
|
558f963648 | ||
|
|
f5883d4840 | ||
|
|
bfdecac3ba | ||
|
|
43a765479a | ||
|
|
07b33b68ab | ||
|
|
e83b118904 | ||
|
|
fb798290a5 | ||
|
|
46c33b4d1e | ||
|
|
3492e7f949 | ||
|
|
5a5b861f69 | ||
|
|
17938ddb3f | ||
|
|
3ea065a620 | ||
|
|
2f6f8044b8 | ||
|
|
7a17eb12dc | ||
|
|
dd8d9b3e3f | ||
|
|
22fc04f06a | ||
|
|
9a121ec62e | ||
|
|
7909bc95ee | ||
|
|
cad11997f4 | ||
|
|
908a7a2695 | ||
|
|
d5b4bdbf6b | ||
|
|
bc482345ce | ||
|
|
a04416e7e7 | ||
|
|
a04eb341e1 | ||
|
|
687c1bbb67 | ||
|
|
4462ee9bc2 | ||
|
|
2379a6fd86 | ||
|
|
99462978cc | ||
|
|
ae7c32a32d | ||
|
|
6e4b23293f | ||
|
|
21a017a8ba | ||
|
|
5a99e66427 | ||
|
|
786e88eef5 | ||
|
|
bb45041dec | ||
|
|
0f92ba3e63 | ||
|
|
25b065eef4 | ||
|
|
dcd35b4686 | ||
|
|
a9fc2305eb | ||
|
|
7f741cec1b | ||
|
|
c03e8f2d67 | ||
|
|
4691444545 | ||
|
|
970e6c4af2 | ||
|
|
31e0376e62 | ||
|
|
cc24dad2cd | ||
|
|
74a36c6918 | ||
|
|
ab0472005e | ||
|
|
e171a8c845 | ||
|
|
5de055a350 | ||
|
|
3c04194dfd | ||
|
|
aee54309d8 | ||
|
|
5831fdfa3e | ||
|
|
5267cdfbeb | ||
|
|
6094b577ef | ||
|
|
b1f734166f | ||
|
|
52060d1393 | ||
|
|
9a1589259f | ||
|
|
12ae9a1b74 | ||
|
|
ed7395db70 | ||
|
|
6a63556fd2 | ||
|
|
4ecfce4a5d | ||
|
|
6f827a68c0 | ||
|
|
8afdf966f3 | ||
|
|
e9e5533372 | ||
|
|
e8acdad270 | ||
|
|
d11116544c | ||
|
|
4741028cc2 | ||
|
|
56af44885d | ||
|
|
cc30864ada | ||
|
|
5291f78895 | ||
|
|
731f4da92a | ||
|
|
da6615ad6f | ||
|
|
251c763245 | ||
|
|
ac29692485 | ||
|
|
2e0e8f6956 | ||
|
|
74e1532079 | ||
|
|
2657bca277 | ||
|
|
9704adba03 | ||
|
|
a1960cb749 | ||
|
|
b288117b4f | ||
|
|
c22f3f3191 | ||
|
|
3b4e0a8dbc | ||
|
|
6ef9445b46 | ||
|
|
55856e9ff0 | ||
|
|
8b8585f86c | ||
|
|
ad427fa6b4 | ||
|
|
3d4519e2bd | ||
|
|
d0f0454a0c | ||
|
|
e0601e75fa | ||
|
|
a4951a264b | ||
|
|
b8485a1c3e | ||
|
|
54b4f47b6a | ||
|
|
c558909fd0 | ||
|
|
da3f02f855 | ||
|
|
f1ea93719c | ||
|
|
fc59f65fca | ||
|
|
bddf072511 | ||
|
|
f5a4cc3c1d | ||
|
|
a7e1430898 | ||
|
|
d0cb4b5b17 | ||
|
|
f5055d744e | ||
|
|
8d308b0a7c | ||
|
|
1515cd7478 | ||
|
|
604a5c0c9f | ||
|
|
ba46931979 | ||
|
|
7d620595d2 | ||
|
|
d186adbbbb | ||
|
|
3bc6794948 | ||
|
|
f5e0f90e11 | ||
|
|
536e0e3cf8 | ||
|
|
b82c2acf67 | ||
|
|
bd46971ad8 | ||
|
|
61cbae6a3f | ||
|
|
d9c13333ed | ||
|
|
6716339317 | ||
|
|
49b4388491 | ||
|
|
6300416593 | ||
|
|
c7aa6123b2 | ||
|
|
df17c47dd4 | ||
|
|
5e8962917b | ||
|
|
112b72d2ed | ||
|
|
3d3bf1d092 | ||
|
|
e5f7fc4cef | ||
|
|
bf82694b6e | ||
|
|
d1fa52c8dc | ||
|
|
577d1dceea | ||
|
|
9b4e3172c3 | ||
|
|
b7db3a42b5 | ||
|
|
a8292e5183 | ||
|
|
bf2b95fda7 | ||
|
|
3f1550096c | ||
|
|
860beafd74 | ||
|
|
66839a01d6 | ||
|
|
cf4fbdc8fc | ||
|
|
f2a1a0596d | ||
|
|
40e72a4c00 | ||
|
|
30cae266b0 | ||
|
|
d54708b2c4 | ||
|
|
f33d35a45b | ||
|
|
de1f64aa6b | ||
|
|
a325b66034 | ||
|
|
031ed59108 | ||
|
|
8e78d74568 | ||
|
|
1c3b462a8f | ||
|
|
ee25e8f218 | ||
|
|
573c074aef | ||
|
|
53b55ac7f6 | ||
|
|
f054b131e4 | ||
|
|
f80ae8e806 | ||
|
|
5464fed1a8 | ||
|
|
b4311d02d4 | ||
|
|
7778182f02 | ||
|
|
b5fb766f3d | ||
|
|
d236131171 | ||
|
|
f88c0d5161 | ||
|
|
9eab1cd1c1 | ||
|
|
a68cefd27c | ||
|
|
71ce42476b | ||
|
|
e795470ea7 | ||
|
|
f87f721487 | ||
|
|
962c79e3dc | ||
|
|
2ef0c9334d | ||
|
|
f18bb3a3de | ||
|
|
d724932660 | ||
|
|
4de9a308bd | ||
|
|
1760731fab | ||
|
|
88e554d26b | ||
|
|
50dac60b65 | ||
|
|
c2fb75cdc5 | ||
|
|
560acb7626 | ||
|
|
394571144d | ||
|
|
35fef64623 | ||
|
|
fdaca5f804 | ||
|
|
716fe16487 | ||
|
|
7d63433f65 | ||
|
|
ea122c0e77 | ||
|
|
f0d71bc65b | ||
|
|
c33b2b0946 | ||
|
|
0475c18b0f | ||
|
|
8396d7cbd7 | ||
|
|
66e34014b9 | ||
|
|
908c108116 | ||
|
|
8130bb3bb7 | ||
|
|
0813f1425f | ||
|
|
3f9ca54c61 | ||
|
|
03c49bc5cc | ||
|
|
7007834394 | ||
|
|
e7ee37c218 | ||
|
|
5590b4fde2 | ||
|
|
1750692328 | ||
|
|
03ceda4f77 | ||
|
|
110f596cf6 | ||
|
|
63288ab589 | ||
|
|
c9480bea8f | ||
|
|
3a78307c2e | ||
|
|
89ed205b50 | ||
|
|
490edf1859 | ||
|
|
5fb42b9c6d | ||
|
|
d5e07fc788 | ||
|
|
c3c871f9cc | ||
|
|
72635b8c8f | ||
|
|
057d895aaf | ||
|
|
407fc1240a | ||
|
|
2bc307c564 | ||
|
|
c42790e6f2 | ||
|
|
ecdbea2aab | ||
|
|
7cb98456b1 | ||
|
|
4f80317b14 | ||
|
|
7a589d65a3 | ||
|
|
acd5d04ee9 | ||
|
|
998c85e393 | ||
|
|
70478bd1fa | ||
|
|
4c06feeb50 | ||
|
|
2acd6d5ce0 | ||
|
|
56e7c0c7d0 | ||
|
|
7948070be6 | ||
|
|
a9139fcca0 | ||
|
|
99b3dc65a7 | ||
|
|
599c7a175e | ||
|
|
0a03dc652c | ||
|
|
53f72c2192 | ||
|
|
53334ad3dc | ||
|
|
4d7ddf7be1 | ||
|
|
9dfdd0841f | ||
|
|
7f662291e4 | ||
|
|
9bbd32424e | ||
|
|
41b5fe3a19 | ||
|
|
d35195a591 | ||
|
|
ee229d3711 | ||
|
|
9eb12a5348 | ||
|
|
0bb8343f0b | ||
|
|
d5c13f5c26 | ||
|
|
9e57fe1531 | ||
|
|
8b10e0d9f0 | ||
|
|
45d7dc90b3 | ||
|
|
da2683391d | ||
|
|
ea50830dae | ||
|
|
985a7ca973 | ||
|
|
2c649bed07 | ||
|
|
78fad54d6a | ||
|
|
05c583fd81 | ||
|
|
b99912abd6 | ||
|
|
c3a5a8a4e8 | ||
|
|
ad451fd9c9 | ||
|
|
ce31e0cfff | ||
|
|
545dcea3e8 | ||
|
|
29accb2e6f | ||
|
|
8d59fdc732 | ||
|
|
a7fe18fd65 | ||
|
|
e80835c380 | ||
|
|
622bb87b89 | ||
|
|
3d3c9876eb | ||
|
|
ea588be0f7 | ||
|
|
71f2d3b87a | ||
|
|
8d0670d05c | ||
|
|
1b6eccfb36 | ||
|
|
9a7c2cedf5 | ||
|
|
55b9a6bf9f | ||
|
|
ff1f564527 | ||
|
|
6ef61221bf | ||
|
|
2edbe0df08 | ||
|
|
a96dc90104 | ||
|
|
3e8b966dc8 | ||
|
|
1ee94f10c4 | ||
|
|
74866edadb | ||
|
|
e402ebc14c | ||
|
|
ab48de6e9b | ||
|
|
314b905e8f | ||
|
|
db60c0fefb | ||
|
|
713d9464a2 | ||
|
|
84cc4a35d4 | ||
|
|
6a64b8658a | ||
|
|
b8ee827068 | ||
|
|
8fea1b6e3d | ||
|
|
96934f5f22 | ||
|
|
a2ad4d30e7 | ||
|
|
0623588019 | ||
|
|
f1d087da44 | ||
|
|
5dca4a0fd3 | ||
|
|
7d085274de | ||
|
|
1da9184a14 | ||
|
|
a7757e547c |
14
.github/workflows/compile.yml
vendored
14
.github/workflows/compile.yml
vendored
@@ -39,6 +39,20 @@ jobs:
|
||||
- run: cd CommonServer && npm install
|
||||
- run: cd ApiReference && npm install && npm run compile
|
||||
|
||||
compile-link-shortner:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
- run: cd Common && npm install
|
||||
- run: cd Model && npm install
|
||||
- run: cd CommonServer && npm install
|
||||
- run: cd LinkShortner && npm install && npm run compile
|
||||
|
||||
compile-common-server:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
|
||||
29
.github/workflows/docker-build.yml
vendored
29
.github/workflows/docker-build.yml
vendored
@@ -25,6 +25,21 @@ jobs:
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./Accounts/Dockerfile .
|
||||
|
||||
docker-build-link-shortner:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image for accounts service
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./LinkShortner/Dockerfile .
|
||||
|
||||
docker-build-api-reference:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
@@ -191,20 +206,6 @@ jobs:
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./Notification/Dockerfile .
|
||||
|
||||
docker-build-nginx:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image for mail service
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./Nginx/Dockerfile ./Nginx
|
||||
|
||||
docker-build-probe:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
1276
.github/workflows/release.yml
vendored
1276
.github/workflows/release.yml
vendored
File diff suppressed because it is too large
Load Diff
442
.github/workflows/test-release.yml
vendored
442
.github/workflows/test-release.yml
vendored
@@ -1,442 +0,0 @@
|
||||
name: Test Image Deploy to DockerHub
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
|
||||
generate-build-number:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
build_number: ${{ steps.buildnumber.outputs.build_number }}
|
||||
steps:
|
||||
- name: Generate build number
|
||||
id: buildnumber
|
||||
uses: onyxmueller/build-tag-number@v1.0.2
|
||||
with:
|
||||
token: ${{secrets.github_token}}
|
||||
- run: echo "Build number is ${{ steps.buildnumber.outputs.build_number }}"
|
||||
|
||||
test-server-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/test-server:$ONEUPTIME_VERSION-test --tag oneuptime/test-server:test --push -f ./TestServer/Dockerfile .
|
||||
|
||||
workflow-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/workflow:$ONEUPTIME_VERSION-test --tag oneuptime/workflow:test --push -f ./Workflow/Dockerfile .
|
||||
|
||||
workers-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy workers.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/workers:$ONEUPTIME_VERSION-test --tag oneuptime/workers:test --push -f ./Workers/Dockerfile .
|
||||
|
||||
status-page-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy status-page.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/status-page:$ONEUPTIME_VERSION-test --tag oneuptime/status-page:test --push -f ./StatusPage/Dockerfile .
|
||||
|
||||
realtime-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy realtime.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/realtime:$ONEUPTIME_VERSION-test --tag oneuptime/realtime:test --push -f ./Realtime/Dockerfile .
|
||||
|
||||
|
||||
probe-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy probe-api.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/probe:$ONEUPTIME_VERSION-test --tag oneuptime/probe:test --push -f ./Probe/Dockerfile .
|
||||
|
||||
probe-api-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy probe-api.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/probe-api:$ONEUPTIME_VERSION-test --tag oneuptime/probe-api:test --push -f ./ProbeAPI/Dockerfile .
|
||||
|
||||
nginx-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/nginx:$ONEUPTIME_VERSION-test --tag oneuptime/nginx:test --push -f ./Nginx/Dockerfile .
|
||||
|
||||
|
||||
notification-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/notification:$ONEUPTIME_VERSION-test --tag oneuptime/notification:test --push -f ./Notification/Dockerfile .
|
||||
|
||||
|
||||
licensing-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/licensing:$ONEUPTIME_VERSION-test --tag oneuptime/licensing:test --push -f ./Licensing/Dockerfile .
|
||||
|
||||
integrations-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/integrations:$ONEUPTIME_VERSION-test --tag oneuptime/integrations:test --push -f ./Integration/Dockerfile .
|
||||
|
||||
|
||||
|
||||
|
||||
identity-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/identity:$ONEUPTIME_VERSION-test --tag oneuptime/identity:test --push -f ./Identity/Dockerfile .
|
||||
|
||||
|
||||
home-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/home:$ONEUPTIME_VERSION-test --tag oneuptime/home:test --push -f ./Home/Dockerfile .
|
||||
|
||||
|
||||
helm-chart-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/helm-chart:$ONEUPTIME_VERSION-test --tag oneuptime/helm-chart:test --push -f ./HelmChart/Dockerfile .
|
||||
|
||||
|
||||
haraka-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/haraka:$ONEUPTIME_VERSION-test --tag oneuptime/haraka:test --push -f ./Haraka/Dockerfile .
|
||||
|
||||
file-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy file.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/file:$ONEUPTIME_VERSION-test --tag oneuptime/file:test --push -f ./File/Dockerfile .
|
||||
|
||||
|
||||
|
||||
dashboard-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy dashboard-api.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/dashboard:$ONEUPTIME_VERSION-test --tag oneuptime/dashboard:test --push -f ./Dashboard/Dockerfile .
|
||||
|
||||
|
||||
|
||||
|
||||
dashboard-api-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy dashboard-api.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/dashboard-api:$ONEUPTIME_VERSION-test --tag oneuptime/dashboard-api:test --push -f ./DashboardAPI/Dockerfile .
|
||||
|
||||
|
||||
|
||||
|
||||
api-reference-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy api-reference.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/api-reference:$ONEUPTIME_VERSION-test --tag oneuptime/api-reference:test --push -f ./ApiReference/Dockerfile .
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
accounts-test-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKERHUB_PASSWORD: ${{secrets.DOCKERHUB_PASSWORD}}
|
||||
DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
|
||||
ONEUPTIME_VERSION: "7.0.${{needs.generate-build-number.outputs.build_number}}"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- run: npm run prerun
|
||||
- run: sudo docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
|
||||
# Build and deploy accounts.
|
||||
- run: sudo docker login --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD
|
||||
- run: sudo docker buildx create --use
|
||||
- run: sudo docker buildx build --platform linux/amd64,linux/arm64 --tag oneuptime/accounts:$ONEUPTIME_VERSION-test --tag oneuptime/accounts:test --push -f ./Accounts/Dockerfile .
|
||||
|
||||
|
||||
2
.github/workflows/test.common-server.yaml
vendored
2
.github/workflows/test.common-server.yaml
vendored
@@ -20,4 +20,4 @@ jobs:
|
||||
- run: cd Common && npm install
|
||||
- run: cd Model && npm install
|
||||
- run: cd CommonServer && bash test-setup.sh
|
||||
- run: cd CommonServer && npm install && npm run test
|
||||
- run: export $(grep -v '^#' config.env | xargs) && cd CommonServer && npm install && npm run test
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -69,12 +69,10 @@ secret.env
|
||||
config.env
|
||||
config.env.tmp
|
||||
config.env.temp
|
||||
docker-compose.yml
|
||||
logs.txt
|
||||
|
||||
*/Cert.crt
|
||||
*/Key.key
|
||||
Nginx/default.conf
|
||||
|
||||
Certs/StatusPageCerts/*.crt
|
||||
Certs/StatusPageCerts/*.key
|
||||
@@ -85,3 +83,5 @@ Certs/ServerCerts/*.key
|
||||
Backups/*.backup
|
||||
Backups/*.sql
|
||||
Backups/*.tar
|
||||
|
||||
.env
|
||||
|
||||
44
.vscode/launch.json
vendored
44
.vscode/launch.json
vendored
@@ -41,6 +41,34 @@
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/ApiReference",
|
||||
"name": "API Reference: Debug with Docker",
|
||||
"port": 9178,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/LinkShortner",
|
||||
"name": "Link Shortner: Debug with Docker",
|
||||
"port": 9826,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/TestServer",
|
||||
@@ -58,7 +86,7 @@
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Probe",
|
||||
"name": "Dashboard API: Debug with Docker",
|
||||
"name": "Probe: Debug with Docker",
|
||||
"port": 9655,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
@@ -307,20 +335,6 @@
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/probe",
|
||||
"name": "Probe: Debug with Docker",
|
||||
"port": 9238,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"name": "CommonServer: Debug Tests",
|
||||
"type": "node",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
PORT=3003
|
||||
@@ -1 +0,0 @@
|
||||
PORT={{ .Env.ACCOUNTS_PORT }}
|
||||
@@ -73,6 +73,8 @@ EXPOSE 3003
|
||||
|
||||
|
||||
{{ if eq .Env.ENVIRONMENT "development" }}
|
||||
RUN mkdir /usr/src/app/dev-env
|
||||
RUN touch /usr/src/app/dev-env/.env
|
||||
#Run the app
|
||||
CMD [ "npm", "run", "dev" ]
|
||||
{{ else }}
|
||||
|
||||
1
Accounts/dev-env/README.md
Normal file
1
Accounts/dev-env/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This is where env will be stored for the dev environment. This is where you will find the .env file when you exec into the container.
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"watch": ["webpack.config.js"],
|
||||
"exec": "export DEBUG=express:* && webpack-dev-server --port=3003 --mode=development"
|
||||
"exec": "export DEBUG=express:* && printenv > /usr/src/app/dev-env/.env && webpack-dev-server --port=3003 --mode=development"
|
||||
}
|
||||
203
Accounts/package-lock.json
generated
203
Accounts/package-lock.json
generated
@@ -7,7 +7,6 @@
|
||||
"": {
|
||||
"name": "accounts",
|
||||
"version": "0.1.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"Common": "file:../Common",
|
||||
"CommonServer": "file:../CommonServer",
|
||||
@@ -57,6 +56,7 @@
|
||||
"@types/uuid": "^8.3.4",
|
||||
"axios": "^0.26.1",
|
||||
"crypto-js": "^4.1.1",
|
||||
"json5": "^2.2.3",
|
||||
"moment": "^2.29.2",
|
||||
"moment-timezone": "^0.5.40",
|
||||
"nanoid": "^3.3.2",
|
||||
@@ -88,12 +88,14 @@
|
||||
"@types/ejs": "^3.1.1",
|
||||
"@types/gridfs-stream": "^0.5.35",
|
||||
"@types/json2csv": "^5.0.3",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/nodemailer": "^6.4.7",
|
||||
"airtable": "^0.11.3",
|
||||
"axios": "^1.3.3",
|
||||
"bullmq": "^3.6.6",
|
||||
"Common": "file:../Common",
|
||||
"cors": "^2.8.5",
|
||||
"cron-parser": "^4.8.1",
|
||||
"dotenv": "^16.0.0",
|
||||
"ejs": "^3.1.8",
|
||||
"express": "^4.17.3",
|
||||
@@ -101,6 +103,7 @@
|
||||
"handlebars": "^4.7.7",
|
||||
"json2csv": "^5.0.7",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"Model": "file:../Model",
|
||||
"node-device-detector": "^2.0.0",
|
||||
"nodemailer": "^6.7.3",
|
||||
@@ -109,6 +112,7 @@
|
||||
"redis": "^4.2.0",
|
||||
"socket.io": "^4.4.1",
|
||||
"stripe": "^10.17.0",
|
||||
"twilio": "^4.13.0",
|
||||
"typeorm": "^0.3.10",
|
||||
"typeorm-extension": "^2.2.13",
|
||||
"vm2": "^3.9.14",
|
||||
@@ -283,9 +287,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -316,9 +320,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/eslint-parser/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -390,9 +394,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -449,9 +453,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -1782,9 +1786,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -1994,9 +1998,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -4836,9 +4840,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -7060,9 +7064,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -7134,9 +7138,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -9150,9 +9154,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-lib-instrument/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -10430,9 +10434,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -10796,9 +10800,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
@@ -12886,9 +12890,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-app-rewired/node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
@@ -13647,9 +13651,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@@ -14647,9 +14651,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tough-cookie": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||
"dependencies": {
|
||||
"psl": "^1.1.33",
|
||||
"punycode": "^2.1.1",
|
||||
@@ -15645,9 +15649,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -16135,9 +16139,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -16157,9 +16161,9 @@
|
||||
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -16214,9 +16218,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -16257,9 +16261,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -17120,9 +17124,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -17277,9 +17281,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -19339,9 +19343,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -19848,6 +19852,7 @@
|
||||
"axios": "^0.26.1",
|
||||
"crypto-js": "^4.1.1",
|
||||
"jest": "^27.5.1",
|
||||
"json5": "^2.2.3",
|
||||
"moment": "^2.29.2",
|
||||
"moment-timezone": "^0.5.40",
|
||||
"nanoid": "^3.3.2",
|
||||
@@ -19891,6 +19896,7 @@
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/json2csv": "^5.0.3",
|
||||
"@types/jsonwebtoken": "^8.5.9",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/node": "^17.0.22",
|
||||
"@types/nodemailer": "^6.4.7",
|
||||
"airtable": "^0.11.3",
|
||||
@@ -19898,6 +19904,7 @@
|
||||
"bullmq": "^3.6.6",
|
||||
"Common": "file:../Common",
|
||||
"cors": "^2.8.5",
|
||||
"cron-parser": "^4.8.1",
|
||||
"dotenv": "^16.0.0",
|
||||
"ejs": "^3.1.8",
|
||||
"express": "^4.17.3",
|
||||
@@ -19906,6 +19913,7 @@
|
||||
"jest": "^27.5.1",
|
||||
"json2csv": "^5.0.7",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"Model": "file:../Model",
|
||||
"node-device-detector": "^2.0.0",
|
||||
"nodemailer": "^6.7.3",
|
||||
@@ -19915,6 +19923,7 @@
|
||||
"socket.io": "^4.4.1",
|
||||
"stripe": "^10.17.0",
|
||||
"ts-jest": "^27.1.4",
|
||||
"twilio": "^4.13.0",
|
||||
"typeorm": "^0.3.10",
|
||||
"typeorm-extension": "^2.2.13",
|
||||
"vm2": "^3.9.14",
|
||||
@@ -21163,9 +21172,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -21210,9 +21219,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -22615,9 +22624,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -23597,9 +23606,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -23879,9 +23888,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
@@ -25195,9 +25204,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -25728,9 +25737,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
@@ -26499,9 +26508,9 @@
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||
"requires": {
|
||||
"psl": "^1.1.33",
|
||||
"punycode": "^2.1.1",
|
||||
@@ -27202,9 +27211,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA=="
|
||||
},
|
||||
"workbox-background-sync": {
|
||||
"version": "6.5.4",
|
||||
|
||||
@@ -65,7 +65,7 @@ const ForgotPassword: FunctionComponent = () => {
|
||||
formType={FormType.Create}
|
||||
maxPrimaryButtonWidth={true}
|
||||
footer={
|
||||
<div className="actions pointer text-center mt-4 underline-on-hover fw-semibold">
|
||||
<div className="actions pointer text-center mt-4 hover:underline fw-semibold">
|
||||
<p>
|
||||
<Link
|
||||
to={new Route('/accounts/login')}
|
||||
|
||||
@@ -79,7 +79,7 @@ const LoginPage: FunctionComponent = () => {
|
||||
}}
|
||||
maxPrimaryButtonWidth={true}
|
||||
footer={
|
||||
<div className="actions pointer text-center mt-4 underline-on-hover fw-semibold">
|
||||
<div className="actions pointer text-center mt-4 hover:underline fw-semibold">
|
||||
<p>
|
||||
{!showSsoTip && (
|
||||
<div
|
||||
|
||||
@@ -9,9 +9,10 @@ import LoginUtil from '../Utils/Login';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import UserUtil from 'CommonUI/src/Utils/User';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import { DASHBOARD_URL } from 'CommonUI/src/Config';
|
||||
import { BILLING_ENABLED, DASHBOARD_URL } from 'CommonUI/src/Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { SIGNUP_API_URL } from '../Utils/ApiPaths';
|
||||
import Fields from 'CommonUI/src/Components/Forms/Types/Fields';
|
||||
|
||||
const RegisterPage: FunctionComponent = () => {
|
||||
const apiUrl: URL = SIGNUP_API_URL;
|
||||
@@ -20,6 +21,80 @@ const RegisterPage: FunctionComponent = () => {
|
||||
Navigation.navigate(DASHBOARD_URL);
|
||||
}
|
||||
|
||||
let formFields: Fields<User> = [
|
||||
{
|
||||
field: {
|
||||
email: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Email,
|
||||
placeholder: 'jeff@example.com',
|
||||
required: true,
|
||||
title: 'Email',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
placeholder: 'Jeff Smith',
|
||||
required: true,
|
||||
title: 'Full Name',
|
||||
},
|
||||
];
|
||||
|
||||
if (BILLING_ENABLED) {
|
||||
formFields = formFields.concat([
|
||||
{
|
||||
field: {
|
||||
companyName: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
placeholder: 'Acme, Inc.',
|
||||
required: true,
|
||||
title: 'Company Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyPhoneNumber: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Phone,
|
||||
required: true,
|
||||
placeholder: '+11234567890',
|
||||
title: 'Phone Number',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
formFields = formFields.concat([
|
||||
{
|
||||
field: {
|
||||
password: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Password,
|
||||
validation: {
|
||||
minLength: 6,
|
||||
},
|
||||
placeholder: 'Password',
|
||||
title: 'Password',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
confirmPassword: true,
|
||||
} as any,
|
||||
validation: {
|
||||
minLength: 6,
|
||||
toMatchField: 'password',
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Password,
|
||||
placeholder: 'Confirm Password',
|
||||
title: 'Confirm Password',
|
||||
overideFieldKey: 'confirmPassword',
|
||||
required: true,
|
||||
forceShow: true,
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
@@ -56,71 +131,7 @@ const RegisterPage: FunctionComponent = () => {
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
}}
|
||||
fields={[
|
||||
{
|
||||
field: {
|
||||
email: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Email,
|
||||
placeholder: 'jeff@example.com',
|
||||
required: true,
|
||||
title: 'Email',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
placeholder: 'Jeff Smith',
|
||||
required: true,
|
||||
title: 'Full Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyName: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
placeholder: 'Acme, Inc.',
|
||||
required: true,
|
||||
title: 'Company Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyPhoneNumber: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Phone,
|
||||
required: true,
|
||||
placeholder: '+11234567890',
|
||||
title: 'Phone Number',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
password: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Password,
|
||||
validation: {
|
||||
minLength: 6,
|
||||
},
|
||||
placeholder: 'Password',
|
||||
title: 'Password',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
confirmPassword: true,
|
||||
},
|
||||
validation: {
|
||||
minLength: 6,
|
||||
toMatchField: 'password',
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Password,
|
||||
placeholder: 'Confirm Password',
|
||||
title: 'Confirm Password',
|
||||
overideFieldKey: 'confirmPassword',
|
||||
required: true,
|
||||
forceShow: true,
|
||||
},
|
||||
]}
|
||||
fields={formFields}
|
||||
apiUrl={apiUrl}
|
||||
formType={FormType.Create}
|
||||
submitButtonText={'Sign Up'}
|
||||
|
||||
@@ -109,7 +109,7 @@ const VerifyEmail: FunctionComponent = () => {
|
||||
'/accounts/login'
|
||||
)
|
||||
}
|
||||
className="underline-on-hover text-primary fw-semibold"
|
||||
className="hover:underline text-primary fw-semibold"
|
||||
>
|
||||
Login.
|
||||
</Link>
|
||||
|
||||
@@ -38,9 +38,7 @@ module.exports = {
|
||||
new webpack.DefinePlugin({
|
||||
'process': {
|
||||
'env': {
|
||||
...readEnvFile('../Common/.env'),
|
||||
...readEnvFile('../CommonUI/.env'),
|
||||
...readEnvFile('./.env')
|
||||
...readEnvFile('/usr/src/app/dev-env/.env')
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
PORT={{ .Env.API_DOCS_PORT }}
|
||||
@@ -20,7 +20,7 @@ import DataTypeServiceHandler from './Service/DataType';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
|
||||
const ResourceDictionary: Dictionary<ModelDocumentation> =
|
||||
ResourceUtil.getReosurceDictionaryByPath();
|
||||
ResourceUtil.getResourceDictionaryByPath();
|
||||
|
||||
const APP_NAME: string = 'reference';
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import PageNotFoundServiceHandler from './PageNotFound';
|
||||
|
||||
const Resources: Array<ModelDocumentation> = ResourceUtil.getResources();
|
||||
const ResourceDictionary: Dictionary<ModelDocumentation> =
|
||||
ResourceUtil.getReosurceDictionaryByPath();
|
||||
ResourceUtil.getResourceDictionaryByPath();
|
||||
|
||||
const PermissionDictionary: Dictionary<PermissionProps> =
|
||||
PermissionHelper.getAllPermissionPropsAsDictionary();
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class ResourceUtil {
|
||||
);
|
||||
}
|
||||
|
||||
public static getReosurceDictionaryByPath(): Dictionary<ModelDocumentation> {
|
||||
public static getResourceDictionaryByPath(): Dictionary<ModelDocumentation> {
|
||||
const dict: Dictionary<ModelDocumentation> = {};
|
||||
|
||||
const resources: Array<ModelDocumentation> =
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="font-bold text-xl">API Documentation</h1>
|
||||
<p class="lead">Use the OneUptime API to access any reosurce in your projects, create automated
|
||||
<p class="lead">Use the OneUptime API to access any resource in your projects, create automated
|
||||
workflows, and more
|
||||
and
|
||||
seamlessly integrate your project into the other tools and services you use in your
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
CLICKHOUSE_USER={{ .Env.CLICKHOUSE_USER }}
|
||||
CLICKHOUSE_PASSWORD={{ .Env.CLICKHOUSE_PASSWORD }}
|
||||
CLICKHOUSE_DB=oneuptime
|
||||
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1
|
||||
3
Clickhouse/README.md
Normal file
3
Clickhouse/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Clickhouse
|
||||
|
||||
This folder is for clickhouse related files.
|
||||
@@ -1,9 +0,0 @@
|
||||
NODE_ENV={{ .Env.ENVIRONMENT }}
|
||||
BILLING_ENABLED={{ .Env.BILLING_ENABLED }}
|
||||
BILLING_PUBLIC_KEY={{ .Env.BILLING_PUBLIC_KEY }}
|
||||
SUBSCRIPTION_PLAN_BASIC={{ .Env.SUBSCRIPTION_PLAN_BASIC }}
|
||||
SUBSCRIPTION_PLAN_GROWTH={{ .Env.SUBSCRIPTION_PLAN_GROWTH }}
|
||||
SUBSCRIPTION_PLAN_SCALE={{ .Env.SUBSCRIPTION_PLAN_SCALE }}
|
||||
SUBSCRIPTION_PLAN_ENTERPRISE={{ .Env.SUBSCRIPTION_PLAN_ENTERPRISE }}
|
||||
METERED_PLAN_ACTIVE_MONITORING={{ .Env.METERED_PLAN_ACTIVE_MONITORING }}
|
||||
DOMAIN={{ .Env.DOMAIN }}
|
||||
@@ -28,13 +28,17 @@ import Permission, {
|
||||
UserPermission,
|
||||
UserTenantAccessPermission,
|
||||
} from '../Types/Permission';
|
||||
import { ColumnAccessControl } from '../Types/Database/AccessControl/AccessControl';
|
||||
import {
|
||||
ColumnAccessControl,
|
||||
ColumnBillingAccessControl,
|
||||
} from '../Types/Database/AccessControl/AccessControl';
|
||||
import { getColumnAccessControlForAllColumns } from '../Types/Database/AccessControl/ColumnAccessControl';
|
||||
import BadDataException from '../Types/Exception/BadDataException';
|
||||
import { PlanSelect } from '../Types/Billing/SubscriptionPlan';
|
||||
import { EnableWorkflowOn } from '../Types/Model/EnableWorkflow';
|
||||
import IconProp from '../Types/Icon/IconProp';
|
||||
import Text from '../Types/Text';
|
||||
import { getColumnBillingAccessControlForAllColumns } from '../Types/Database/AccessControl/ColumnBillingAccessControl';
|
||||
|
||||
export type DbTypes =
|
||||
| string
|
||||
@@ -202,6 +206,14 @@ export default class BaseModel extends BaseEntity {
|
||||
return dictionary[columnName] as TableColumnMetadata;
|
||||
}
|
||||
|
||||
public getColumnBillingAccessControl(
|
||||
columnName: string
|
||||
): ColumnBillingAccessControl {
|
||||
const dictionary: Dictionary<ColumnBillingAccessControl> =
|
||||
getColumnBillingAccessControlForAllColumns(this);
|
||||
return dictionary[columnName] as ColumnBillingAccessControl;
|
||||
}
|
||||
|
||||
public getColumnAccessControlFor(
|
||||
columnName: string
|
||||
): ColumnAccessControl | null {
|
||||
|
||||
@@ -3,6 +3,7 @@ enum HTTPMethod {
|
||||
POST = 'POST',
|
||||
DELETE = 'DELETE',
|
||||
PUT = 'PUT',
|
||||
HEAD = 'HEAD',
|
||||
}
|
||||
|
||||
export default HTTPMethod;
|
||||
|
||||
30
Common/Types/Call/CallRequest.ts
Normal file
30
Common/Types/Call/CallRequest.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import URL from '../API/URL';
|
||||
import Phone from '../Phone';
|
||||
|
||||
export interface Say {
|
||||
sayMessage: string;
|
||||
}
|
||||
|
||||
export interface OnCallInputRequest {
|
||||
[x: string]: Say; // input.
|
||||
default: Say; // what if there is no input or invalid input.
|
||||
}
|
||||
|
||||
export interface GatherInput {
|
||||
introMessage: string;
|
||||
numDigits: number;
|
||||
timeoutInSeconds: number;
|
||||
noInputMessage: string;
|
||||
onInputCallRequest: OnCallInputRequest;
|
||||
responseUrl: URL;
|
||||
}
|
||||
|
||||
export enum CallAction {}
|
||||
|
||||
export interface CallRequestMessage {
|
||||
data: Array<Say | CallAction | GatherInput>;
|
||||
}
|
||||
|
||||
export default interface CallRequest extends CallRequestMessage {
|
||||
to: Phone;
|
||||
}
|
||||
9
Common/Types/Call/CallStatus.ts
Normal file
9
Common/Types/Call/CallStatus.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
enum CallStatus {
|
||||
Success = 'Success',
|
||||
Error = 'Error',
|
||||
LowBalance = 'Low Balance',
|
||||
MissedCall = 'Missed Call',
|
||||
Busy = 'Busy',
|
||||
}
|
||||
|
||||
export default CallStatus;
|
||||
@@ -17,3 +17,9 @@ export interface BillingAccessControl {
|
||||
update: PlanSelect;
|
||||
delete: PlanSelect;
|
||||
}
|
||||
|
||||
export interface ColumnBillingAccessControl {
|
||||
create: PlanSelect;
|
||||
read: PlanSelect;
|
||||
update: PlanSelect;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'reflect-metadata';
|
||||
import BaseModel from '../../../Models/BaseModel';
|
||||
import Dictionary from '../../Dictionary';
|
||||
import { ReflectionMetadataType } from '../../Reflection';
|
||||
import { ColumnBillingAccessControl } from './AccessControl';
|
||||
|
||||
const accessControlSymbol: Symbol = Symbol('ColumnBillingAccessControl');
|
||||
|
||||
export default (
|
||||
accessControl: ColumnBillingAccessControl
|
||||
): ReflectionMetadataType => {
|
||||
return Reflect.metadata(accessControlSymbol, accessControl);
|
||||
};
|
||||
|
||||
export const getColumnBillingAccessControl: Function = (
|
||||
target: BaseModel,
|
||||
propertyKey: string
|
||||
): ColumnBillingAccessControl => {
|
||||
return Reflect.getMetadata(
|
||||
accessControlSymbol,
|
||||
target,
|
||||
propertyKey
|
||||
) as ColumnBillingAccessControl;
|
||||
};
|
||||
|
||||
export const getColumnBillingAccessControlForAllColumns: Function = <
|
||||
T extends BaseModel
|
||||
>(
|
||||
target: T
|
||||
): Dictionary<ColumnBillingAccessControl> => {
|
||||
const dictonary: Dictionary<ColumnBillingAccessControl> = {};
|
||||
const keys: Array<string> = Object.keys(target);
|
||||
|
||||
for (const key of keys) {
|
||||
if (Reflect.getMetadata(accessControlSymbol, target, key)) {
|
||||
dictonary[key] = Reflect.getMetadata(
|
||||
accessControlSymbol,
|
||||
target,
|
||||
key
|
||||
) as ColumnBillingAccessControl;
|
||||
}
|
||||
}
|
||||
|
||||
return dictonary;
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import TableColumnType from './TableColumnType';
|
||||
|
||||
enum ColumnLength {
|
||||
Version = 30,
|
||||
Slug = 100,
|
||||
@@ -15,4 +17,53 @@ enum ColumnLength {
|
||||
OTP = 8,
|
||||
}
|
||||
|
||||
export const getMaxLengthFromTableColumnType: Function = (
|
||||
type: TableColumnType
|
||||
): number | undefined => {
|
||||
if (type === TableColumnType.Version) {
|
||||
return ColumnLength.Version;
|
||||
}
|
||||
if (type === TableColumnType.Slug) {
|
||||
return ColumnLength.Slug;
|
||||
}
|
||||
if (type === TableColumnType.Email) {
|
||||
return ColumnLength.Email;
|
||||
}
|
||||
if (type === TableColumnType.Domain) {
|
||||
return ColumnLength.Domain;
|
||||
}
|
||||
if (type === TableColumnType.Color) {
|
||||
return ColumnLength.Color;
|
||||
}
|
||||
if (type === TableColumnType.Name) {
|
||||
return ColumnLength.Name;
|
||||
}
|
||||
if (type === TableColumnType.Description) {
|
||||
return ColumnLength.Description;
|
||||
}
|
||||
if (type === TableColumnType.LongText) {
|
||||
return ColumnLength.LongText;
|
||||
}
|
||||
if (type === TableColumnType.Password) {
|
||||
return ColumnLength.Password;
|
||||
}
|
||||
if (type === TableColumnType.ShortURL) {
|
||||
return ColumnLength.ShortURL;
|
||||
}
|
||||
if (type === TableColumnType.ShortText) {
|
||||
return ColumnLength.ShortText;
|
||||
}
|
||||
if (type === TableColumnType.HashedString) {
|
||||
return ColumnLength.HashedString;
|
||||
}
|
||||
if (type === TableColumnType.Phone) {
|
||||
return ColumnLength.Phone;
|
||||
}
|
||||
if (type === TableColumnType.OTP) {
|
||||
return ColumnLength.OTP;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export default ColumnLength;
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface TableColumnMetadata {
|
||||
type: TableColumnType;
|
||||
canReadOnRelationQuery?: boolean;
|
||||
modelType?: { new (): BaseModel };
|
||||
forceGetDefaultValueOnCreate?: () => string | number | boolean; // overwrites any value that is being passed and generates a new one. Useful for generating OTPs, etc.
|
||||
}
|
||||
|
||||
export default (props: TableColumnMetadata): ReflectionMetadataType => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import InBetween from './Database/InBetween';
|
||||
import BadDataException from './Exception/BadDataException';
|
||||
import { JSONObject } from './JSON';
|
||||
import { JSONObject, ObjectType } from './JSON';
|
||||
import PositiveNumber from './PositiveNumber';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
@@ -65,6 +66,21 @@ export default class OneUptimeDate {
|
||||
return YYYY + '-' + MM + '-' + DD + 'T' + HH + ':' + II + ':' + SS;
|
||||
}
|
||||
|
||||
public static fromJSON(json: JSONObject): Date {
|
||||
if (json['_type'] === ObjectType.DateTime) {
|
||||
return OneUptimeDate.fromString(json['value'] as string);
|
||||
}
|
||||
|
||||
throw new BadDataException('Invalid JSON: ' + JSON.stringify(json));
|
||||
}
|
||||
|
||||
public static toJSON(date: Date): JSONObject {
|
||||
return {
|
||||
_type: ObjectType.DateTime,
|
||||
value: OneUptimeDate.toString(date),
|
||||
};
|
||||
}
|
||||
|
||||
public static addRemoveMinutes(date: Date, minutes: number): Date {
|
||||
date = this.fromString(date);
|
||||
return moment(date).add(minutes, 'minutes').toDate();
|
||||
@@ -364,6 +380,18 @@ export default class OneUptimeDate {
|
||||
);
|
||||
}
|
||||
|
||||
public static getDifferenceInMinutes(date: Date, date2: Date): number {
|
||||
date = this.fromString(date);
|
||||
date2 = this.fromString(date2);
|
||||
const minutes: number = moment(date).diff(moment(date2), 'minutes');
|
||||
|
||||
if (minutes < 0) {
|
||||
return minutes * -1;
|
||||
}
|
||||
|
||||
return minutes;
|
||||
}
|
||||
|
||||
public static getDateAsFormattedArrayInMultipleTimezones(
|
||||
date: string | Date,
|
||||
onlyShowDate?: boolean
|
||||
@@ -449,6 +477,10 @@ export default class OneUptimeDate {
|
||||
);
|
||||
}
|
||||
|
||||
public static getDayInSeconds(): number {
|
||||
return 24 * 60 * 60;
|
||||
}
|
||||
|
||||
public static getCurrentTimezoneString(): string {
|
||||
return moment.tz(moment.tz.guess()).zoneAbbr();
|
||||
}
|
||||
@@ -495,4 +527,13 @@ export default class OneUptimeDate {
|
||||
const formatstring: string = 'YYYY-MM-DD';
|
||||
return moment(date).local().format(formatstring);
|
||||
}
|
||||
|
||||
public static asFilterDateForDatabaseQuery(date: string | Date): InBetween {
|
||||
date = this.fromString(date);
|
||||
const formattedDate: Date = moment(date).toDate();
|
||||
return new InBetween(
|
||||
OneUptimeDate.getStartOfDay(formattedDate),
|
||||
OneUptimeDate.getEndOfDay(formattedDate)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class Domain extends DatabaseProperty {
|
||||
'|'
|
||||
);
|
||||
const secondTLDs: Array<string> =
|
||||
'ac|academy|accountant|accountants|actor|adult|ag|agency|ai|airforce|am|amsterdam|apartments|app|archi|army|art|asia|associates|at|attorney|au|auction|auto|autos|baby|band|bar|barcelona|bargains|basketball|bayern|be|beauty|beer|berlin|best|bet|bid|bike|bingo|bio|biz|biz.pl|black|blog|blue|boats|boston|boutique|broker|build|builders|business|buzz|bz|ca|cab|cafe|camera|camp|capital|car|cards|care|careers|cars|casa|cash|casino|catering|cc|center|ceo|ch|charity|chat|cheap|church|city|cl|claims|cleaning|clinic|clothing|cloud|club|cn|co|co.in|co.jp|co.kr|co.nz|co.uk|co.za|coach|codes|coffee|college|com|com.ag|com.au|com.br|com.bz|com.cn|com.co|com.es|com.ky|com.mx|com.pe|com.ph|com.pl|com.ru|com.tw|community|company|computer|condos|construction|consulting|contact|contractors|cooking|cool|country|coupons|courses|credit|creditcard|cricket|cruises|cymru|cz|dance|date|dating|de|deals|degree|delivery|democrat|dental|dentist|design|dev|diamonds|digital|direct|directory|discount|dk|doctor|dog|domains|download|earth|education|email|energy|engineer|engineering|enterprises|equipment|es|estate|eu|events|exchange|expert|exposed|express|fail|faith|family|fan|fans|farm|fashion|film|finance|financial|firm.in|fish|fishing|fit|fitness|flights|florist|fm|football|forsale|foundation|fr|fun|fund|furniture|futbol|fyi|gallery|games|garden|gay|gen.in|gg|gifts|gives|giving|glass|global|gmbh|gold|golf|graphics|gratis|green|gripe|group|gs|guide|guru|hair|haus|health|healthcare|hockey|holdings|holiday|homes|horse|hospital|host|house|idv.tw|immo|immobilien|in|inc|ind.in|industries|info|info.pl|ink|institute|insure|international|investments|io|irish|ist|istanbul|it|jetzt|jewelry|jobs|jp|kaufen|kids|kim|kitchen|kiwi|kr|ky|la|land|lat|law|lawyer|lease|legal|lgbt|life|lighting|limited|limo|live|llc|llp|loan|loans|london|love|ltd|ltda|luxury|maison|makeup|management|market|marketing|mba|me|me.uk|media|melbourne|memorial|men|menu|miami|mobi|moda|moe|money|monster|mortgage|motorcycles|movie|ms|music|mx|nagoya|name|navy|ne.kr|net|net.ag|net.au|net.br|net.bz|net.cn|net.co|net.in|net.ky|net.nz|net.pe|net.ph|net.pl|net.ru|network|news|ninja|nl|no|nom.co|nom.es|nom.pe|nrw|nyc|okinawa|one|onl|online|org|org.ag|org.au|org.cn|org.es|org.in|org.ky|org.nz|org.pe|org.ph|org.pl|org.ru|org.uk|organic|page|paris|partners|parts|party|pe|pet|ph|photography|photos|pictures|pink|pizza|pl|place|plumbing|plus|poker|porn|press|pro|productions|promo|properties|protection|pub|pw|quebec|quest|racing|re.kr|realestate|recipes|red|rehab|reise|reisen|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rich|rip|rocks|rodeo|rugby|run|ryukyu|sale|salon|sarl|school|schule|science|se|security|services|sex|sg|sh|shiksha|shoes|shop|shopping|show|singles|site|ski|skin|soccer|social|software|solar|solutions|space|storage|store|stream|studio|study|style|supplies|supply|support|surf|surgery|sydney|systems|tax|taxi|team|tech|technology|tel|tennis|theater|theatre|tickets|tienda|tips|tires|today|tokyo|tools|tours|town|toys|trade|trading|training|travel|tube|tv|tw|uk|university|uno|us|vacations|vc|vegas|ventures|vet|viajes|video|villas|vin|vip|vision|vodka|vote|voto|voyage|wales|watch|web|webcam|website|wedding|wiki|win|wine|work|works|world|ws|wtf|xxx|xyz|yachts|yoga|yokohama|zone|移动|dev|com|edu|gov|net|mil|org|nom|sch|caa|res|off|gob|int|tur|ip6|uri|urn|asn|act|nsw|qld|tas|vic|pro|biz|adm|adv|agr|arq|art|ato|bio|bmd|cim|cng|cnt|ecn|eco|emp|eng|esp|etc|eti|far|fnd|fot|fst|g12|ggf|imb|ind|inf|jor|jus|leg|lel|mat|med|mus|not|ntr|odo|ppg|psc|psi|qsl|rec|slg|srv|teo|tmp|trd|vet|zlg|web|ltd|sld|pol|fin|k12|lib|pri|aip|fie|eun|sci|prd|cci|pvt|mod|idv|rel|sex|gen|nic|abr|bas|cal|cam|emr|fvg|laz|lig|lom|mar|mol|pmn|pug|sar|sic|taa|tos|umb|vao|vda|ven|mie|北海道|和歌山|神奈川|鹿児島|ass|rep|tra|per|ngo|soc|grp|plc|its|air|and|bus|can|ddr|jfk|mad|nrw|nyc|ski|spy|tcm|ulm|usa|war|fhs|vgs|dep|eid|fet|fla|flå|gol|hof|hol|sel|vik|cri|iwi|ing|abo|fam|gok|gon|gop|gos|aid|atm|gsm|sos|elk|waw|est|aca|bar|cpa|jur|law|sec|plo|www|bir|cbg|jar|khv|msk|nov|nsk|ptz|rnd|spb|stv|tom|tsk|udm|vrn|cmw|kms|nkz|snz|pub|fhv|red|ens|nat|rns|rnu|bbs|tel|bel|kep|nhs|dni|fed|isa|nsn|gub|e12|tec|орг|обр|упр|alt|nis|jpn|mex|ath|iki|nid|gda|inc'.split(
|
||||
'ac|academy|accountant|accountants|actor|adult|ag|agency|ai|airforce|am|amsterdam|apartments|app|archi|army|art|asia|associates|at|attorney|au|auction|auto|autos|baby|band|bar|barcelona|bargains|basketball|bayern|be|beauty|beer|berlin|best|bet|bid|bike|bingo|bio|biz|biz.pl|black|blog|blue|boats|boston|boutique|broker|build|builders|business|buzz|bz|ca|cab|cafe|camera|camp|capital|car|cards|care|careers|cars|casa|cash|casino|catering|cc|center|ceo|ch|charity|chat|cheap|church|city|cl|claims|cleaning|clinic|clothing|cloud|club|cn|co|co.in|co.jp|co.kr|co.nz|co.uk|co.za|coach|codes|coffee|college|com|com.ag|com.au|com.br|com.bz|com.cn|com.co|com.es|com.ky|com.mx|com.pe|com.ph|com.pl|com.ru|com.tw|community|company|computer|condos|construction|consulting|contact|contractors|cooking|cool|country|coupons|courses|credit|creditcard|cricket|cruises|cymru|cz|dance|date|dating|de|deals|degree|delivery|democrat|dental|dentist|design|dev|diamonds|digital|direct|directory|discount|dk|doctor|dog|domains|download|earth|education|email|energy|engineer|engineering|enterprises|equipment|es|estate|eu|events|exchange|expert|exposed|express|fail|faith|family|fan|fans|farm|fashion|film|finance|financial|firm.in|fish|fishing|fit|fitness|flights|florist|fm|football|forsale|foundation|fr|fun|fund|furniture|futbol|fyi|gallery|games|garden|gay|gen.in|gg|gifts|gives|giving|glass|global|gmbh|gold|golf|graphics|gratis|green|gripe|group|gs|guide|guru|hair|haus|health|healthcare|hockey|holdings|holiday|homes|horse|hospital|host|house|idv.tw|immo|immobilien|in|inc|ind.in|industries|info|info.pl|ink|institute|insure|international|investments|io|irish|ist|istanbul|it|jetzt|jewelry|jobs|jp|kaufen|kids|kim|kitchen|kiwi|kr|ky|la|land|lat|law|lawyer|lease|legal|lgbt|life|lighting|limited|limo|live|llc|llp|loan|loans|london|love|ltd|ltda|luxury|maison|makeup|management|market|marketing|mba|me|me.uk|media|melbourne|memorial|men|menu|miami|mobi|moda|moe|money|monster|mortgage|motorcycles|movie|ms|music|mx|nagoya|name|navy|ne.kr|net|net.ag|net.au|net.br|net.bz|net.cn|net.co|net.in|net.ky|net.nz|net.pe|net.ph|net.pl|net.ru|network|news|ninja|nl|no|nom.co|nom.es|nom.pe|nrw|nyc|okinawa|one|onl|online|org|org.ag|org.au|org.cn|org.es|org.in|org.ky|org.nz|org.pe|org.ph|org.pl|org.ru|org.uk|organic|page|paris|partners|parts|party|pe|pet|ph|photography|photos|pictures|pink|pizza|pl|place|plumbing|plus|poker|porn|press|pro|productions|promo|properties|protection|pub|pw|quebec|quest|racing|re.kr|realestate|recipes|red|rehab|reise|reisen|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rich|rip|rocks|rodeo|rugby|run|ryukyu|sale|salon|sarl|school|schule|science|se|security|services|sex|sg|sh|shiksha|shoes|shop|shopping|show|singles|site|ski|skin|soccer|social|software|solar|solutions|space|storage|store|stream|studio|study|style|supplies|supply|support|surf|surgery|sydney|systems|tax|taxi|team|tech|technology|tel|tennis|theater|theatre|tickets|tienda|tips|tires|today|tokyo|tools|tours|town|toys|trade|trading|training|travel|tube|tv|tw|uk|university|uno|us|vacations|vc|vegas|ventures|vet|viajes|video|villas|vin|vip|vision|vodka|vote|voto|voyage|wales|watch|web|webcam|website|wedding|wiki|win|wine|work|works|world|ws|wtf|xxx|xyz|yachts|yoga|yokohama|zone|移动|dev|com|edu|gov|net|mil|org|nom|sch|caa|res|off|gob|int|tur|ip6|uri|urn|asn|act|nsw|qld|tas|vic|pro|biz|adm|adv|agr|arq|art|ato|bio|bmd|cim|cng|cnt|ecn|eco|emp|eng|esp|etc|eti|far|fnd|fot|fst|g12|ggf|imb|ind|inf|jor|jus|leg|lel|mat|med|mus|not|ntr|odo|ppg|psc|psi|qsl|rec|slg|srv|teo|tmp|trd|vet|zlg|web|ltd|sld|pol|fin|k12|lib|pri|aip|fie|eun|sci|prd|cci|pvt|mod|idv|rel|sex|gen|nic|abr|bas|cal|cam|emr|fvg|laz|lig|lom|mar|mol|pmn|pug|sar|sic|taa|tos|umb|vao|vda|ven|mie|北海道|和歌山|神奈川|鹿児島|ass|rep|tra|per|ngo|soc|grp|plc|its|air|and|bus|can|ddr|jfk|mad|nrw|nyc|ski|spy|tcm|ulm|usa|war|fhs|vgs|dep|eid|fet|fla|flå|gol|hof|hol|sel|vik|cri|iwi|ing|abo|fam|gok|gon|gop|gos|aid|atm|gsm|sos|elk|waw|est|aca|bar|cpa|jur|law|sec|plo|www|bir|cbg|jar|khv|msk|nov|nsk|ptz|rnd|spb|stv|tom|tsk|udm|vrn|cmw|kms|nkz|snz|pub|fhv|red|ens|nat|rns|rnu|bbs|tel|bel|kep|nhs|dni|fed|isa|nsn|gub|e12|tec|орг|обр|упр|alt|nis|jpn|mex|ath|iki|nid|gda|inc|za'.split(
|
||||
'|'
|
||||
);
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@ import Email from '../Email';
|
||||
import Dictionary from '../Dictionary';
|
||||
import EmailTemplateType from './EmailTemplateType';
|
||||
|
||||
export default interface EmailMessage {
|
||||
toEmail: Email;
|
||||
export interface EmailEnvelope {
|
||||
subject: string;
|
||||
templateType?: EmailTemplateType;
|
||||
vars: Dictionary<string>;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
export default interface EmailMessage extends EmailEnvelope {
|
||||
toEmail: Email;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import Email from '../Email';
|
||||
import Port from '../Port';
|
||||
import Hostname from '../API/Hostname';
|
||||
import ObjectID from '../ObjectID';
|
||||
|
||||
export default interface EmailServer {
|
||||
id?: ObjectID | undefined; // If this is custom SMTP, this is the ID of the SMTP config. Otherwise, it's undefined
|
||||
host: Hostname;
|
||||
port: Port;
|
||||
username: string;
|
||||
|
||||
@@ -32,6 +32,8 @@ enum EmailTemplateType {
|
||||
StatusPageOwnerAdded = 'StatusPageOwnerAdded.hbs',
|
||||
StatusPageOwnerAnnouncementPosted = 'StatusPageOwnerAnnouncementPosted.hbs',
|
||||
SimpleMessage = 'SimpleMessage.hbs',
|
||||
VerificationCode = 'VerificationCode.hbs',
|
||||
AcknowledgeIncident = 'AcknowledgeIncident.hbs',
|
||||
}
|
||||
|
||||
export default EmailTemplateType;
|
||||
|
||||
@@ -94,6 +94,14 @@ enum IconProp {
|
||||
TransparentCube = 'TransparentCube',
|
||||
Logs = 'Logs',
|
||||
Bolt = 'Bolt',
|
||||
BarsArrowUp = 'BarsArrowUp',
|
||||
BarsArrowDown = 'BarsArrowDown',
|
||||
Bell = 'Bell',
|
||||
BellRinging = 'BellRinging',
|
||||
AdjustmentVertical = 'AdjustmentVertical',
|
||||
AdjustmentHorizontal = 'AdjustmentHorizontal',
|
||||
Minus = 'Minus',
|
||||
MinusSmall = 'MinusSmall',
|
||||
}
|
||||
|
||||
export default IconProp;
|
||||
|
||||
@@ -22,6 +22,7 @@ import { BaseEntity } from 'typeorm';
|
||||
import EqualToOrNull from './Database/EqualToOrNull';
|
||||
import NotEqual from './Database/NotEqual';
|
||||
import { CheckOn, FilterType } from './Monitor/CriteriaFilter';
|
||||
import CallRequest from './Call/CallRequest';
|
||||
|
||||
export enum ObjectType {
|
||||
ObjectID = 'ObjectID',
|
||||
@@ -122,6 +123,7 @@ export type JSONValue =
|
||||
| Array<JSONValue>
|
||||
| Array<Permission>
|
||||
| Array<JSONValue>
|
||||
| CallRequest
|
||||
| undefined
|
||||
| null;
|
||||
|
||||
|
||||
@@ -10,6 +10,16 @@ import SerializableObjectDictionary from './SerializableObjectDictionary';
|
||||
import JSON5 from 'json5';
|
||||
|
||||
export default class JSONFunctions {
|
||||
public static isEmptyObject(
|
||||
obj: JSONObject | BaseModel | null | undefined
|
||||
): boolean {
|
||||
if (!obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Object.keys(obj).length === 0;
|
||||
}
|
||||
|
||||
public static toJSON(
|
||||
model: BaseModel,
|
||||
modelType: { new (): BaseModel }
|
||||
@@ -159,9 +169,13 @@ export default class JSONFunctions {
|
||||
}
|
||||
|
||||
public static fromJSONObject<T extends BaseModel>(
|
||||
json: JSONObject,
|
||||
json: JSONObject | T,
|
||||
type: { new (): T }
|
||||
): T {
|
||||
if (json instanceof BaseModel) {
|
||||
return json;
|
||||
}
|
||||
|
||||
return this.fromJSON<T>(json, type) as T;
|
||||
}
|
||||
|
||||
|
||||
6
Common/Types/Mail/MailStatus.ts
Normal file
6
Common/Types/Mail/MailStatus.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
enum MailStatus {
|
||||
Success = 'Success',
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
export default MailStatus;
|
||||
@@ -4,4 +4,7 @@ export interface CriteriaIncident {
|
||||
title: string;
|
||||
description: string;
|
||||
incidentSeverityId?: ObjectID | undefined;
|
||||
autoResolveIncident?: boolean | undefined;
|
||||
id: string;
|
||||
onCallPolicyIds?: Array<ObjectID> | undefined;
|
||||
}
|
||||
|
||||
@@ -117,6 +117,9 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
||||
title: `${arg.monitorType} monitor is offline`,
|
||||
description: `${arg.monitorType} monitor is currently offline.`,
|
||||
incidentSeverityId: arg.incidentSeverityId,
|
||||
autoResolveIncident: true,
|
||||
id: ObjectID.generate().toString(),
|
||||
onCallPolicyIds: [],
|
||||
},
|
||||
],
|
||||
changeMonitorStatus: true,
|
||||
@@ -151,6 +154,9 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
||||
title: `${arg.monitorType} monitor is offline`,
|
||||
description: `${arg.monitorType} monitor is currently offline.`,
|
||||
incidentSeverityId: arg.incidentSeverityId,
|
||||
autoResolveIncident: true,
|
||||
id: ObjectID.generate().toString(),
|
||||
onCallPolicyIds: [],
|
||||
},
|
||||
],
|
||||
changeMonitorStatus: true,
|
||||
|
||||
7
Common/Types/NotificationRule/NotificationRuleType.ts
Normal file
7
Common/Types/NotificationRule/NotificationRuleType.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
enum NoticationRuleType {
|
||||
ON_CALL_INCIDENT_CREATED = 'When incident is created during on call',
|
||||
WHEN_USER_GOES_ON_CALL = 'When user goes on call',
|
||||
WHEN_USER_GOES_OFF_CALL = 'When user goes off call',
|
||||
}
|
||||
|
||||
export default NoticationRuleType;
|
||||
@@ -0,0 +1,25 @@
|
||||
enum NotificationSettingEventType {
|
||||
// Incident
|
||||
SEND_INCIDENT_CREATED_OWNER_NOTIFICATION = 'Send incident created notification when I am the owner of the incident',
|
||||
SEND_INCIDENT_NOTE_POSTED_OWNER_NOTIFICATION = 'Send incident note posted notification when I am the owner of the incident',
|
||||
SEND_INCIDENT_STATE_CHANGED_OWNER_NOTIFICATION = 'Send incident state changed notification when I am the owner of the incident',
|
||||
SEND_INCIDENT_OWNER_ADDED_NOTIFICATION = 'Send notification when I am added as a owner to the incident',
|
||||
|
||||
// Monitors
|
||||
SEND_MONITOR_OWNER_ADDED_NOTIFICATION = 'Send notification when I am added as a owner to the monitor',
|
||||
SEND_MONITOR_CREATED_OWNER_NOTIFICATION = 'Send monitor created notification when I am the owner of the monitor',
|
||||
SEND_MONITOR_STATUS_CHANGED_OWNER_NOTIFICATION = 'Send monitor status changed notification when I am the owner of the monitor',
|
||||
|
||||
// Scheduled Maintenance
|
||||
SEND_SCHEDULED_MAINTENANCE_CREATED_OWNER_NOTIFICATION = 'Send scheduled maintenance created notification when I am the owner of the scheduled maintenance',
|
||||
SEND_SCHEDULED_MAINTENANCE_NOTE_POSTED_OWNER_NOTIFICATION = 'Send scheduled maintenance note posted notification when I am the owner of the scheduled maintenance',
|
||||
SEND_SCHEDULED_MAINTENANCE_OWNER_ADDED_NOTIFICATION = 'Send notification when I am added as a owner to the scheduled maintenance',
|
||||
SEND_SCHEDULED_MAINTENANCE_STATE_CHANGED_OWNER_NOTIFICATION = 'Send scheduled maintenance state changed notification when I am the owner of the scheduled maintenance',
|
||||
|
||||
// Status Page
|
||||
SEND_STATUS_PAGE_ANNOUNCEMENT_CREATED_OWNER_NOTIFICATION = 'Send status page announcement created notification when I am the owner of the status page',
|
||||
SEND_STATUS_PAGE_CREATED_OWNER_NOTIFICATION = 'Send status page created notification when I am the owner of the status page',
|
||||
SEND_STATUS_PAGE_OWNER_ADDED_NOTIFICATION = 'Send notification when I am added as a owner to the status page',
|
||||
}
|
||||
|
||||
export default NotificationSettingEventType;
|
||||
@@ -19,6 +19,10 @@ export default class ObjectID extends DatabaseProperty {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public equals(other: ObjectID): boolean {
|
||||
return this.id.toString() === other.id.toString();
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
enum OnCallDutyExecutionLogTimelineStatus {
|
||||
Skipped = 'Skipped',
|
||||
Started = 'Started',
|
||||
Executing = 'Executing',
|
||||
SuccessfullyAcknowledged = 'Successfully Acknowledged',
|
||||
NotificationSent = 'Notification Sent',
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
export default OnCallDutyExecutionLogTimelineStatus;
|
||||
@@ -0,0 +1,7 @@
|
||||
enum OnCallDutyPolicyStatus {
|
||||
SuccessfullyAcknowledged = 'Successfully Acknowledged',
|
||||
FailedToAcknowledge = 'Failed to Acknowledge',
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
export default OnCallDutyPolicyStatus;
|
||||
9
Common/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.ts
Normal file
9
Common/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
enum OnCallDutyPolicyStatus {
|
||||
Scheduled = 'Scheduled',
|
||||
Started = 'Started',
|
||||
Executing = 'Executing',
|
||||
Completed = 'Execution Completed',
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
export default OnCallDutyPolicyStatus;
|
||||
@@ -63,6 +63,11 @@ enum Permission {
|
||||
CanEditMonitorCustomField = 'CanEditMonitorCustomField',
|
||||
CanReadMonitorCustomField = 'CanReadMonitorCustomField',
|
||||
|
||||
CanCreateOnCallDutyPolicyCustomField = 'CanCreateOnCallDutyPolicyCustomField',
|
||||
CanDeleteOnCallDutyPolicyCustomField = 'CanDeleteOnCallDutyPolicyCustomField',
|
||||
CanEditOnCallDutyPolicyCustomField = 'CanEditOnCallDutyPolicyCustomField',
|
||||
CanReadOnCallDutyPolicyCustomField = 'CanReadOnCallDutyPolicyCustomField',
|
||||
|
||||
CanCreateScheduledMaintenanceCustomField = 'CanCreateScheduledMaintenanceCustomField',
|
||||
CanDeleteScheduledMaintenanceCustomField = 'CanDeleteScheduledMaintenanceCustomField',
|
||||
CanEditScheduledMaintenanceCustomField = 'CanEditScheduledMaintenanceCustomField',
|
||||
@@ -73,10 +78,9 @@ enum Permission {
|
||||
CanEditMonitorProbe = 'CanEditMonitorProbe',
|
||||
CanReadMonitorProbe = 'CanReadMonitorProbe',
|
||||
|
||||
CanCreateSmsLog = 'CanCreateSmsLog',
|
||||
CanDeleteSmsLog = 'CanDeleteSmsLog',
|
||||
CanEditSmsLog = 'CanEditSmsLog',
|
||||
CanReadSmsLog = 'CanReadSmsLog',
|
||||
CanReadEmailLog = 'CanReadEmailLog',
|
||||
CanReadCallLog = 'CanReadCallLog',
|
||||
|
||||
CanCreateIncidentOwnerTeam = 'CanCreateIncidentOwnerTeam',
|
||||
CanDeleteIncidentOwnerTeam = 'CanDeleteIncidentOwnerTeam',
|
||||
@@ -251,6 +255,12 @@ enum Permission {
|
||||
CanReadIncidentStateTimeline = 'CanReadIncidentStateTimeline',
|
||||
CanDeleteIncidentStateTimeline = 'CanDeleteIncidentStateTimeline',
|
||||
|
||||
// Incident Status Permissions (Owner + Admin Permission by default)
|
||||
CanCreateMonitorStatusTimeline = 'CanCreateMonitorStatusTimeline',
|
||||
CanEditMonitorStatusTimeline = 'CanEditMonitorStatusTimeline',
|
||||
CanReadMonitorStatusTimeline = 'CanReadMonitorStatusTimeline',
|
||||
CanDeleteMonitorStatusTimeline = 'CanDeleteMonitorStatusTimeline',
|
||||
|
||||
// MonitorStatus Permissions (Owner + Admin Permission by default)
|
||||
CanCreateProjectMonitorStatus = 'CanCreateProjectMonitorStatus',
|
||||
CanEditProjectMonitorStatus = 'CanEditProjectMonitorStatus',
|
||||
@@ -296,10 +306,31 @@ enum Permission {
|
||||
CanReadProjectStatusPage = 'CanReadProjectStatusPage',
|
||||
|
||||
// Resource Permissions (Team Permission)
|
||||
CanCreateProjectOnCallDuty = 'CanCreateProjectOnCallDuty',
|
||||
CanEditProjectOnCallDuty = 'CanEditProjectOnCallDuty',
|
||||
CanDeleteProjectOnCallDuty = 'CanDeleteProjectOnCallDuty',
|
||||
CanReadProjectOnCallDuty = 'CanReadProjectOnCallDuty',
|
||||
CanCreateProjectOnCallDutyPolicy = 'CanCreateProjectOnCallDutyPolicy',
|
||||
CanEditProjectOnCallDutyPolicy = 'CanEditProjectOnCallDutyPolicy',
|
||||
CanDeleteProjectOnCallDutyPolicy = 'CanDeleteProjectOnCallDutyPolicy',
|
||||
CanReadProjectOnCallDutyPolicy = 'CanReadProjectOnCallDutyPolicy',
|
||||
|
||||
CanReadProjectOnCallDutyPolicyExecutionLogTimeline = 'CanReadProjectOnCallDutyPolicyExecutionLogTimeline',
|
||||
CanReadProjectOnCallDutyPolicyExecutionLog = 'CanReadProjectOnCallDutyPolicyExecutionLog',
|
||||
|
||||
// Resource Permissions (Team Permission)
|
||||
CanCreateProjectOnCallDutyPolicyEscalationRule = 'CanCreateProjectOnCallDutyPolicyEscalationRule',
|
||||
CanEditProjectOnCallDutyPolicyEscalationRule = 'CanEditProjectOnCallDutyPolicyEscalationRule',
|
||||
CanDeleteProjectOnCallDutyPolicyEscalationRule = 'CanDeleteProjectOnCallDutyPolicyEscalationRule',
|
||||
CanReadProjectOnCallDutyPolicyEscalationRule = 'CanReadProjectOnCallDutyPolicyEscalationRule',
|
||||
|
||||
// Resource Permissions (Team Permission)
|
||||
CanCreateProjectOnCallDutyPolicyEscalationRuleUser = 'CanCreateProjectOnCallDutyPolicyEscalationRuleUser',
|
||||
CanEditProjectOnCallDutyPolicyEscalationRuleUser = 'CanEditProjectOnCallDutyPolicyEscalationRuleUser',
|
||||
CanDeleteProjectOnCallDutyPolicyEscalationRuleUser = 'CanDeleteProjectOnCallDutyPolicyEscalationRuleUser',
|
||||
CanReadProjectOnCallDutyPolicyEscalationRuleUser = 'CanReadProjectOnCallDutyPolicyEscalationRuleUser',
|
||||
|
||||
// Resource Permissions (Team Permission)
|
||||
CanCreateProjectOnCallDutyPolicyEscalationRuleTeam = 'CanCreateProjectOnCallDutyPolicyEscalationRuleTeam',
|
||||
CanEditProjectOnCallDutyPolicyEscalationRuleTeam = 'CanEditProjectOnCallDutyPolicyEscalationRuleTeam',
|
||||
CanDeleteProjectOnCallDutyPolicyEscalationRuleTeam = 'CanDeleteProjectOnCallDutyPolicyEscalationRuleTeam',
|
||||
CanReadProjectOnCallDutyPolicyEscalationRuleTeam = 'CanReadProjectOnCallDutyPolicyEscalationRuleTeam',
|
||||
|
||||
// Project SMTP Config (Team Permission)
|
||||
CanCreateProjectSMTPConfig = 'CanCreateProjectSMTPConfig',
|
||||
@@ -449,7 +480,7 @@ export class PermissionHelper {
|
||||
permission: Permission.ProjectOwner,
|
||||
title: 'Project Owner',
|
||||
description:
|
||||
'Owner of this project, manages billing, inviting other admins to this project, and can delete this project.',
|
||||
'Owner of this project. Manages billing, inviting other admins to this project, and can delete this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
@@ -465,7 +496,14 @@ export class PermissionHelper {
|
||||
permission: Permission.ProjectAdmin,
|
||||
title: 'Project Admin',
|
||||
description:
|
||||
'Owner of this project, manages billing, inviting other admins to this project, and can delete this project.',
|
||||
'Admin of this project. Manages team members in this project, however cannot manage billing or delete this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.ProjectUser,
|
||||
title: 'Project User',
|
||||
description: 'User of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
@@ -654,6 +692,39 @@ export class PermissionHelper {
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateMonitorStatusTimeline,
|
||||
title: 'Can Create Monitor Status Timeline',
|
||||
description:
|
||||
'This permission can create Monitor Status history of an incident in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanDeleteMonitorStatusTimeline,
|
||||
title: 'Can Delete Monitor Status Timeline',
|
||||
description:
|
||||
'This permission can delete Monitor Status history of an incident in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanEditMonitorStatusTimeline,
|
||||
title: 'Can Edit Monitor Status Timeline',
|
||||
description:
|
||||
'This permission can edit Monitor Status history of an incident in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanReadMonitorStatusTimeline,
|
||||
title: 'Can Read Monitor Status Timeline',
|
||||
description:
|
||||
'This permission can read Monitor Status history of an incident in this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateProjectMonitorStatus,
|
||||
title: 'Can Create Monitor Status',
|
||||
@@ -1446,32 +1517,163 @@ export class PermissionHelper {
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateProjectOnCallDuty,
|
||||
title: 'Can Create On-Call Duty',
|
||||
permission:
|
||||
Permission.CanReadProjectOnCallDutyPolicyExecutionLogTimeline,
|
||||
title: 'Can Read On-Call Duty Policy Execution Log Timeline',
|
||||
description:
|
||||
'This permission can read teams in on-call duty execution log timeline.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
|
||||
{
|
||||
permission:
|
||||
Permission.CanReadProjectOnCallDutyPolicyExecutionLog,
|
||||
title: 'Can Read On-Call Duty Policy Execution Log',
|
||||
description:
|
||||
'This permission can read teams in on-call duty execution log.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
|
||||
{
|
||||
permission:
|
||||
Permission.CanCreateProjectOnCallDutyPolicyEscalationRuleTeam,
|
||||
title: 'Can Create On-Call Duty Policy Escalation Rule',
|
||||
description:
|
||||
'This permission can create teams in on-call duty escalation rule this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanDeleteProjectOnCallDutyPolicyEscalationRuleTeam,
|
||||
title: 'Can Delete On-Call Duty Policy Escalation Rule Team',
|
||||
description:
|
||||
'This permission can delete teams in on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanEditProjectOnCallDutyPolicyEscalationRuleTeam,
|
||||
title: 'Can Edit On-Call Duty Policy Escalation Rule Team',
|
||||
description:
|
||||
'This permission can edit teams in on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanReadProjectOnCallDutyPolicyEscalationRuleTeam,
|
||||
title: 'Can Read On-Call Duty Policy Escalation Rule Team',
|
||||
description:
|
||||
'This permission can read teams in on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
|
||||
{
|
||||
permission:
|
||||
Permission.CanCreateProjectOnCallDutyPolicyEscalationRuleUser,
|
||||
title: 'Can Create On-Call Duty Policy Escalation Rule User',
|
||||
description:
|
||||
'This permission can create on-call duty escalation rule this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanDeleteProjectOnCallDutyPolicyEscalationRuleUser,
|
||||
title: 'Can Delete On-Call Duty Policy Escalation Rule User',
|
||||
description:
|
||||
'This permission can delete on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanEditProjectOnCallDutyPolicyEscalationRuleUser,
|
||||
title: 'Can Edit On-Call Duty Policy Escalation Rule User',
|
||||
description:
|
||||
'This permission can edit on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanReadProjectOnCallDutyPolicyEscalationRuleUser,
|
||||
title: 'Can Read On-Call Duty Policy Escalation Rule User',
|
||||
description:
|
||||
'This permission can read on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
|
||||
{
|
||||
permission:
|
||||
Permission.CanCreateProjectOnCallDutyPolicyEscalationRule,
|
||||
title: 'Can Create On-Call Duty Policy Escalation Rule',
|
||||
description:
|
||||
'This permission can create on-call duty escalation rule this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanDeleteProjectOnCallDutyPolicyEscalationRule,
|
||||
title: 'Can Delete On-Call Duty Policy Escalation Rule',
|
||||
description:
|
||||
'This permission can delete on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanEditProjectOnCallDutyPolicyEscalationRule,
|
||||
title: 'Can Edit On-Call Duty Policy Escalation Rule',
|
||||
description:
|
||||
'This permission can edit on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission:
|
||||
Permission.CanReadProjectOnCallDutyPolicyEscalationRule,
|
||||
title: 'Can Read On-Call Duty Policy Escalation Rule',
|
||||
description:
|
||||
'This permission can read on-call duty escalation rule of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateProjectOnCallDutyPolicy,
|
||||
title: 'Can Create On-Call Duty Policy',
|
||||
description:
|
||||
'This permission can create on-call duty this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanDeleteProjectOnCallDuty,
|
||||
title: 'Can Delete On-Call Duty',
|
||||
permission: Permission.CanDeleteProjectOnCallDutyPolicy,
|
||||
title: 'Can Delete On-Call Duty Policy',
|
||||
description:
|
||||
'This permission can delete on-call duty of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanEditProjectOnCallDuty,
|
||||
title: 'Can Edit On-Call Duty',
|
||||
permission: Permission.CanEditProjectOnCallDutyPolicy,
|
||||
title: 'Can Edit On-Call Duty Policy',
|
||||
description:
|
||||
'This permission can edit on-call duty of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: true,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanReadProjectOnCallDuty,
|
||||
title: 'Can Read On-Call Duty',
|
||||
permission: Permission.CanReadProjectOnCallDutyPolicy,
|
||||
title: 'Can Read On-Call Duty Policy',
|
||||
description:
|
||||
'This permission can read on-call duty of this project.',
|
||||
isAssignableToTenant: true,
|
||||
@@ -1541,6 +1743,39 @@ export class PermissionHelper {
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateOnCallDutyPolicyCustomField,
|
||||
title: 'Can Create On Call Policy Custom Field',
|
||||
description:
|
||||
'This permission can create On Call Policy Custom Field this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanDeleteOnCallDutyPolicyCustomField,
|
||||
title: 'Can Delete On Call Policy Custom Field',
|
||||
description:
|
||||
'This permission can delete On Call Policy Custom Field of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanEditOnCallDutyPolicyCustomField,
|
||||
title: 'Can Edit On Call Policy Custom Field',
|
||||
description:
|
||||
'This permission can edit On Call Policy Custom Field of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanReadOnCallDutyPolicyCustomField,
|
||||
title: 'Can Read On Call Policy Custom Field',
|
||||
description:
|
||||
'This permission can read On Call Policy Custom Field of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateMonitorCustomField,
|
||||
title: 'Can Create Monitor Custom Field',
|
||||
@@ -1673,29 +1908,6 @@ export class PermissionHelper {
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateSmsLog,
|
||||
title: 'Can Create SMS Log',
|
||||
description: 'This permission can create SMS Log this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanDeleteSmsLog,
|
||||
title: 'Can Delete SMS Log',
|
||||
description:
|
||||
'This permission can delete SMS Log of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanEditSmsLog,
|
||||
title: 'Can Edit SMS Log',
|
||||
description:
|
||||
'This permission can edit SMS Log of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
{
|
||||
permission: Permission.CanReadSmsLog,
|
||||
title: 'Can Read SMS Log',
|
||||
@@ -1705,6 +1917,15 @@ export class PermissionHelper {
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanReadCallLog,
|
||||
title: 'Can Read Call Log',
|
||||
description:
|
||||
'This permission can read Call Logs of this project.',
|
||||
isAssignableToTenant: true,
|
||||
isAccessControlPermission: false,
|
||||
},
|
||||
|
||||
{
|
||||
permission: Permission.CanCreateMonitorProbe,
|
||||
title: 'Can Create Monitor Probe',
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class Phone extends DatabaseProperty {
|
||||
* }
|
||||
*/
|
||||
const re: RegExp =
|
||||
/^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/; // regex for international phone numbers format based on (ITU-T E.123)
|
||||
/^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,7}$/; // regex for international phone numbers format based on (ITU-T E.123)
|
||||
const isValid: boolean = re.test(v);
|
||||
if (!isValid) {
|
||||
throw new BadDataException(`Phone is not in valid format: ${v}`);
|
||||
|
||||
@@ -5,4 +5,5 @@ export default interface ProbeApiIngestResponse {
|
||||
ingestedMonitorStepId?: ObjectID | undefined;
|
||||
nextMonitorStepId?: ObjectID | undefined;
|
||||
criteriaMetId?: string | undefined;
|
||||
rootCause: string | null;
|
||||
}
|
||||
|
||||
@@ -10,4 +10,5 @@ export default interface ProbeMonitorResponse {
|
||||
responseBody?: string | JSONObject | undefined;
|
||||
monitorStepId: ObjectID;
|
||||
monitorId: ObjectID;
|
||||
probeId: ObjectID;
|
||||
}
|
||||
|
||||
9
Common/Types/SMS/SMS.ts
Normal file
9
Common/Types/SMS/SMS.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import Phone from '../Phone';
|
||||
|
||||
export interface SMSMessage {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export default interface SMS extends SMSMessage {
|
||||
to: Phone;
|
||||
}
|
||||
@@ -26,9 +26,11 @@ import HashedString from './HashedString';
|
||||
import InBetween from './Database/InBetween';
|
||||
import NotNull from './Database/NotNull';
|
||||
import IsNull from './Database/IsNull';
|
||||
import OneUptimeDate from './Date';
|
||||
|
||||
const SerializableObjectDictionary: Dictionary<any> = {
|
||||
[ObjectType.Phone]: Phone,
|
||||
[ObjectType.DateTime]: OneUptimeDate,
|
||||
[ObjectType.ObjectID]: ObjectID,
|
||||
[ObjectType.Name]: Name,
|
||||
[ObjectType.EqualToOrNull]: EqualToOrNull,
|
||||
|
||||
@@ -16,6 +16,22 @@ export default class Text {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static generateRandomNumber(length?: number): string {
|
||||
if (!length) {
|
||||
length = 10;
|
||||
}
|
||||
|
||||
let result: string = '';
|
||||
const characters: string = '12134567890';
|
||||
const charactersLength: number = characters.length;
|
||||
for (let i: number = 0; i < length; i++) {
|
||||
result += characters.charAt(
|
||||
Math.floor(Math.random() * charactersLength)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static convertNumberToWords(num: number): string {
|
||||
const words: Array<string> = [
|
||||
'first',
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
enum UserNotificationEventType {
|
||||
IncidentCreated = 'Incident Created',
|
||||
}
|
||||
|
||||
export default UserNotificationEventType;
|
||||
@@ -0,0 +1,9 @@
|
||||
enum UserNotificationExecutionStatus {
|
||||
Scheduled = 'Scheduled',
|
||||
Started = 'Strated',
|
||||
Executing = 'Executing',
|
||||
Completed = 'Completed',
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
export default UserNotificationExecutionStatus;
|
||||
9
Common/Types/UserNotification/UserNotificationStatus.ts
Normal file
9
Common/Types/UserNotification/UserNotificationStatus.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
enum UserNotificationStatus {
|
||||
Sent = 'Sent',
|
||||
Acknowledged = 'Acknowledged',
|
||||
Error = 'Error',
|
||||
Sending = 'Sending',
|
||||
Skipped = 'Skipped',
|
||||
}
|
||||
|
||||
export default UserNotificationStatus;
|
||||
@@ -1,7 +1,8 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import Headers from './API/Headers';
|
||||
import URL from './API/URL';
|
||||
import HTML from './Html';
|
||||
import HTTPMethod from './API/HTTPMethod';
|
||||
|
||||
export interface WebsiteResponse {
|
||||
url: URL;
|
||||
@@ -13,18 +14,32 @@ export interface WebsiteResponse {
|
||||
}
|
||||
|
||||
export default class WebsiteRequest {
|
||||
public static async get(
|
||||
public static async fetch(
|
||||
url: URL,
|
||||
options: {
|
||||
headers?: Headers | undefined;
|
||||
timeout?: number | undefined;
|
||||
isHeadRequest?: boolean | undefined;
|
||||
}
|
||||
): Promise<WebsiteResponse> {
|
||||
// use axios to fetch an HTML page
|
||||
const response: AxiosResponse = await axios.get(url.toString(), {
|
||||
headers: options.headers || {},
|
||||
const axiosOptions: AxiosRequestConfig = {
|
||||
timeout: options.timeout || 5000,
|
||||
});
|
||||
method: HTTPMethod.GET,
|
||||
};
|
||||
|
||||
if (options.headers) {
|
||||
axiosOptions.headers = options.headers;
|
||||
}
|
||||
|
||||
if (options.isHeadRequest) {
|
||||
axiosOptions.method = HTTPMethod.HEAD;
|
||||
}
|
||||
|
||||
// use axios to fetch an HTML page
|
||||
const response: AxiosResponse = await axios(
|
||||
url.toString(),
|
||||
axiosOptions
|
||||
);
|
||||
|
||||
// return the response
|
||||
return {
|
||||
|
||||
@@ -160,7 +160,7 @@ export default class BaseModelComponent {
|
||||
arguments: [],
|
||||
returnValues: [
|
||||
{
|
||||
id: 'data',
|
||||
id: 'model',
|
||||
name: `${model.singularName}`,
|
||||
description: `${model.singularName} deleted in the database`,
|
||||
type: ComponentInputType.BaseModel,
|
||||
@@ -300,7 +300,7 @@ export default class BaseModelComponent {
|
||||
],
|
||||
returnValues: [
|
||||
{
|
||||
id: 'data',
|
||||
id: 'model',
|
||||
name: `${model.singularName}`,
|
||||
description: `${model.singularName} created in the database`,
|
||||
type: ComponentInputType.BaseModel,
|
||||
@@ -443,7 +443,7 @@ export default class BaseModelComponent {
|
||||
],
|
||||
returnValues: [
|
||||
{
|
||||
id: 'data',
|
||||
id: 'model',
|
||||
name: `${model.singularName}`,
|
||||
description: `Updated ${model.singularName}`,
|
||||
type: ComponentInputType.BaseModel,
|
||||
|
||||
@@ -88,6 +88,24 @@ export default class API {
|
||||
);
|
||||
}
|
||||
|
||||
public async head<
|
||||
T extends JSONObject | JSONArray | BaseModel | Array<BaseModel>
|
||||
>(
|
||||
path: Route,
|
||||
data?: JSONObject | JSONArray,
|
||||
headers?: Headers
|
||||
): Promise<HTTPResponse<T> | HTTPErrorResponse> {
|
||||
return await API.head<T>(
|
||||
new URL(
|
||||
this.protocol,
|
||||
this.hostname,
|
||||
this.baseRoute.addRoute(path)
|
||||
),
|
||||
data,
|
||||
headers
|
||||
);
|
||||
}
|
||||
|
||||
public async put<
|
||||
T extends JSONObject | JSONArray | BaseModel | Array<BaseModel>
|
||||
>(
|
||||
@@ -179,6 +197,16 @@ export default class API {
|
||||
return await this.fetch(HTTPMethod.DELETE, url, data, headers);
|
||||
}
|
||||
|
||||
public static async head<
|
||||
T extends JSONObject | JSONArray | BaseModel | Array<BaseModel>
|
||||
>(
|
||||
url: URL,
|
||||
data?: JSONObject | JSONArray,
|
||||
headers?: Headers
|
||||
): Promise<HTTPResponse<T> | HTTPErrorResponse> {
|
||||
return await this.fetch(HTTPMethod.HEAD, url, data, headers);
|
||||
}
|
||||
|
||||
public static async put<
|
||||
T extends JSONObject | JSONArray | BaseModel | Array<BaseModel>
|
||||
>(
|
||||
|
||||
@@ -3,3 +3,4 @@ export const EVERY_DAY: string = '0 8 * * *';
|
||||
export const EVERY_HOUR: string = '1 * * * *';
|
||||
export const EVERY_FIVE_MINUTE: string = '*/5 * * * *';
|
||||
export const EVERY_FIVE_SECONDS: string = '*/5 * * * * *';
|
||||
export const EVERY_WEEK: string = '0 0 * * 0';
|
||||
|
||||
24
Common/package-lock.json
generated
24
Common/package-lock.json
generated
@@ -4095,9 +4095,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tough-cookie": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"psl": "^1.1.33",
|
||||
@@ -4588,9 +4588,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -7774,9 +7774,9 @@
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"psl": "^1.1.33",
|
||||
@@ -8067,9 +8067,9 @@
|
||||
}
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
|
||||
"dev": true
|
||||
},
|
||||
"wrap-ansi": {
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
ONEUPTIME_SECRET={{ .Env.ONEUPTIME_SECRET }}
|
||||
|
||||
DATABASE_PORT={{ .Env.DATABASE_PORT }}
|
||||
DATABASE_USERNAME={{ .Env.DATABASE_USERNAME }}
|
||||
DATABASE_PASSWORD={{ .Env.DATABASE_PASSWORD }}
|
||||
DATABASE_NAME={{ .Env.DATABASE_NAME }}
|
||||
DATABASE_HOST={{ .Env.DATABASE_HOST }}
|
||||
|
||||
REDIS_PASSWORD={{ .Env.REDIS_PASSWORD }}
|
||||
REDIS_HOST={{ .Env.REDIS_HOST }}
|
||||
REDIS_PORT={{ .Env.REDIS_PORT }}
|
||||
|
||||
ENCRYPTION_SECRET={{ .Env.ENCRYPTION_SECRET }}
|
||||
DISABLE_SIGNUP={{ .Env.DISABLE_SIGNUP }}
|
||||
|
||||
REALTIME_HOSTNAME={{ .Env.REALTIME_HOSTNAME }}
|
||||
NOTIFICATION_HOSTNAME={{ .Env.NOTIFICATION_HOSTNAME }}
|
||||
DASHBOARD_HOSTNAME=d{{ .Env.DASHBOARD_HOSTNAME }}
|
||||
DASHBOARD_API_HOSTNAME={{ .Env.DASHBOARD_API_HOSTNAME }}
|
||||
PROBE_API_HOSTNAME={{ .Env.DATA_INGESTOR_HOSTNAME }}
|
||||
DATA_INGESTOR_HOSTNAME={{ .Env.DATA_INGESTOR_HOSTNAME }}
|
||||
ACCOUNTS_HOSTNAME={{ .Env.ACCOUNTS_HOSTNAME }}
|
||||
HOME_HOSTNAME={{ .Env.HOME_HOSTNAME }}
|
||||
WORKER_HOSTNAME={{ .Env.WORKER_HOSTNAME }}
|
||||
WORKFLOW_HOSTNAME={{ .Env.WORKFLOW_HOSTNAME }}
|
||||
|
||||
BILLING_PRIVATE_KEY={{ .Env.BILLING_PRIVATE_KEY }}
|
||||
BILLING_PUBLIC_KEY={{ .Env.BILLING_PUBLIC_KEY }}
|
||||
BILLING_ENABLED={{ .Env.BILLING_ENABLED }}
|
||||
|
||||
DOMAIN={{ .Env.DOMAIN }}
|
||||
HTTP_PROTOCOL={{ .Env.HTTP_PROTOCOL }}
|
||||
|
||||
REALTIME_ROUTE={{ .Env.REALTIME_ROUTE }}
|
||||
NOTIFICATION_ROUTE={{ .Env.NOTIFICATION_ROUTE }}
|
||||
DASHBOARD_ROUTE={{ .Env.DASHBOARD_ROUTE }}
|
||||
DASHBOARD_API_ROUTE={{ .Env.DASHBOARD_API_ROUTE }}
|
||||
PROBE_API_ROUTE={{ .Env.PROBE_API_ROUTE }}
|
||||
DATA_INGESTOR_ROUTE={{ .Env.DATA_INGESTOR_ROUTE }}
|
||||
ACCOUNTS_ROUTE={{ .Env.ACCOUNTS_ROUTE }}
|
||||
HOME_ROUTE={{ .Env.HOME_ROUTE }}
|
||||
HELMCHARTS_ROUTE={{ .Env.HELMCHARTS_ROUTE }}
|
||||
API_REFERENCE_ROUTE={{ .Env.API_REFERENCE_ROUTE }}
|
||||
IDENTITY_ROUTE={{ .Env.IDENTITY_ROUTE }}
|
||||
FILE_ROUTE={{ .Env.FILE_ROUTE }}
|
||||
WORKFLOW_ROUTE={{ .Env.WORKFLOW_ROUTE }}
|
||||
STATUS_PAGE_ROUTE={{ .Env.STATUS_PAGE_ROUTE }}
|
||||
|
||||
IS_SERVER=true
|
||||
|
||||
ANALYTICS_KEY={{ .Env.ANALYTICS_KEY }}
|
||||
ANALYTICS_HOST={{ .Env.ANALYTICS_HOST }}
|
||||
@@ -609,6 +609,7 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
projectId: statusPage.projectId!,
|
||||
},
|
||||
select: {
|
||||
createdAt: true,
|
||||
note: true,
|
||||
incidentId: true,
|
||||
},
|
||||
@@ -792,6 +793,7 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
projectId: statusPage.projectId!,
|
||||
},
|
||||
select: {
|
||||
createdAt: true,
|
||||
note: true,
|
||||
scheduledMaintenanceId: true,
|
||||
},
|
||||
@@ -1340,6 +1342,7 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
projectId: statusPage.projectId!,
|
||||
},
|
||||
select: {
|
||||
createdAt: true,
|
||||
note: true,
|
||||
scheduledMaintenanceId: true,
|
||||
},
|
||||
@@ -1696,6 +1699,7 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
projectId: statusPage.projectId!,
|
||||
},
|
||||
select: {
|
||||
createdAt: true,
|
||||
note: true,
|
||||
incidentId: true,
|
||||
},
|
||||
|
||||
122
CommonServer/API/UserCallAPI.ts
Normal file
122
CommonServer/API/UserCallAPI.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import UserCall from 'Model/Models/UserCall';
|
||||
import UserCallService, {
|
||||
Service as UserCallServiceType,
|
||||
} from '../Services/UserCallService';
|
||||
import BaseAPI from './BaseAPI';
|
||||
import UserMiddleware from '../Middleware/UserAuthorization';
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
OneUptimeRequest,
|
||||
} from '../Utils/Express';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Response from '../Utils/Response';
|
||||
import UserSMS from 'Model/Models/UserSMS';
|
||||
|
||||
export default class UserCallAPI extends BaseAPI<
|
||||
UserCall,
|
||||
UserCallServiceType
|
||||
> {
|
||||
public constructor() {
|
||||
super(UserCall, UserCallService);
|
||||
|
||||
this.router.post(
|
||||
`/user-call/verify`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body.itemId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
if (!req.body.code) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid code')
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the code matches and verify the phone number.
|
||||
const item: UserSMS | null = await this.service.findOneById({
|
||||
id: req.body['itemId'],
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
userId: true,
|
||||
verificationCode: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Item not found')
|
||||
);
|
||||
}
|
||||
|
||||
//cehck user id
|
||||
|
||||
if (
|
||||
item.userId?.toString() !==
|
||||
(
|
||||
req as OneUptimeRequest
|
||||
)?.userAuthorization?.userId?.toString()
|
||||
) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid user ID')
|
||||
);
|
||||
}
|
||||
|
||||
if (item.verificationCode !== req.body['code']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid code')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.updateOneById({
|
||||
id: item.id!,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
data: {
|
||||
isVerified: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
);
|
||||
|
||||
this.router.post(
|
||||
`/user-call/resend-verification-code`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body.itemId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.resendVerificationCode(req.body.itemId);
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
123
CommonServer/API/UserEmailAPI.ts
Normal file
123
CommonServer/API/UserEmailAPI.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import UserEmail from 'Model/Models/UserEmail';
|
||||
import UserEmailService, {
|
||||
Service as UserEmailServiceType,
|
||||
} from '../Services/UserEmailService';
|
||||
import BaseAPI from './BaseAPI';
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
OneUptimeRequest,
|
||||
} from '../Utils/Express';
|
||||
import UserMiddleware from '../Middleware/UserAuthorization';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Response from '../Utils/Response';
|
||||
|
||||
export default class UserEmailAPI extends BaseAPI<
|
||||
UserEmail,
|
||||
UserEmailServiceType
|
||||
> {
|
||||
public constructor() {
|
||||
super(UserEmail, UserEmailService);
|
||||
|
||||
this.router.post(
|
||||
`${new this.entityType().getCrudApiPath()?.toString()}/verify`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body.itemId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
if (!req.body.code) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid code')
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the code matches and verify the email.
|
||||
const item: UserEmail | null = await this.service.findOneById({
|
||||
id: req.body['itemId'],
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
userId: true,
|
||||
verificationCode: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Item not found')
|
||||
);
|
||||
}
|
||||
|
||||
//cehck user id
|
||||
|
||||
if (
|
||||
item.userId?.toString() !==
|
||||
(
|
||||
req as OneUptimeRequest
|
||||
)?.userAuthorization?.userId?.toString()
|
||||
) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid user ID')
|
||||
);
|
||||
}
|
||||
|
||||
if (item.verificationCode !== req.body['code']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid code')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.updateOneById({
|
||||
id: item.id!,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
data: {
|
||||
isVerified: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
);
|
||||
|
||||
this.router.post(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/resend-verification-code`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body.itemId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.resendVerificationCode(req.body.itemId);
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
161
CommonServer/API/UserOnCallLogTimelineAPI.ts
Normal file
161
CommonServer/API/UserOnCallLogTimelineAPI.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import UserOnCallLogTimeline from 'Model/Models/UserOnCallLogTimeline';
|
||||
import UserOnCallLogTimelineService, {
|
||||
Service as UserNotificationLogTimelineServiceType,
|
||||
} from '../Services/UserOnCallLogTimelineService';
|
||||
import BaseAPI from './BaseAPI';
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
OneUptimeRequest,
|
||||
} from '../Utils/Express';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Response from '../Utils/Response';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import NotificationMiddleware from '../Middleware/NotificationMiddleware';
|
||||
import OneUptimeDate from 'Common/Types/Date';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { DashboardRoute, Domain, HttpProtocol } from '../Config';
|
||||
import UserNotificationStatus from 'Common/Types/UserNotification/UserNotificationStatus';
|
||||
|
||||
export default class UserNotificationLogTimelineAPI extends BaseAPI<
|
||||
UserOnCallLogTimeline,
|
||||
UserNotificationLogTimelineServiceType
|
||||
> {
|
||||
public constructor() {
|
||||
super(UserOnCallLogTimeline, UserOnCallLogTimelineService);
|
||||
|
||||
this.router.post(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/call/gather-input/:itemId`,
|
||||
NotificationMiddleware.isValidCallNotificationRequest,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.params['itemId']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
const token: JSONObject = (req as any).callTokenData;
|
||||
|
||||
const itemId: ObjectID = new ObjectID(req.params['itemId']);
|
||||
|
||||
const timelineItem: UserOnCallLogTimeline | null =
|
||||
await this.service.findOneById({
|
||||
id: itemId,
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
triggeredByIncidentId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!timelineItem) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item Id')
|
||||
);
|
||||
}
|
||||
|
||||
// check digits.
|
||||
|
||||
if (req.body['Digits'] === '1') {
|
||||
// then ack incident
|
||||
await this.service.updateOneById({
|
||||
id: itemId,
|
||||
data: {
|
||||
acknowledgedAt: OneUptimeDate.getCurrentDate(),
|
||||
isAcknowledged: true,
|
||||
status: UserNotificationStatus.Acknowledged,
|
||||
statusMessage: 'Notification Acknowledged',
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return NotificationMiddleware.sendResponse(
|
||||
req,
|
||||
res,
|
||||
token as any
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
this.router.get(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/acknowledge/:itemId`,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.params['itemId']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Item ID is required')
|
||||
);
|
||||
}
|
||||
|
||||
const itemId: ObjectID = new ObjectID(req.params['itemId']);
|
||||
|
||||
const timelineItem: UserOnCallLogTimeline | null =
|
||||
await this.service.findOneById({
|
||||
id: itemId,
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
triggeredByIncidentId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!timelineItem) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item Id')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.updateOneById({
|
||||
id: itemId,
|
||||
data: {
|
||||
acknowledgedAt: OneUptimeDate.getCurrentDate(),
|
||||
isAcknowledged: true,
|
||||
status: UserNotificationStatus.Acknowledged,
|
||||
statusMessage: 'Notification Acknowledged',
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
// redirect to dashboard to incidents page.
|
||||
return Response.redirect(
|
||||
req,
|
||||
res,
|
||||
new URL(
|
||||
HttpProtocol,
|
||||
Domain,
|
||||
DashboardRoute.addRoute(
|
||||
`/${timelineItem.projectId?.toString()}/incidents/${timelineItem.triggeredByIncidentId!.toString()}`
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
118
CommonServer/API/UserSmsAPI.ts
Normal file
118
CommonServer/API/UserSmsAPI.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import UserSMS from 'Model/Models/UserSMS';
|
||||
import UserSMSService, {
|
||||
Service as UserSMSServiceType,
|
||||
} from '../Services/UserSmsService';
|
||||
import BaseAPI from './BaseAPI';
|
||||
import UserMiddleware from '../Middleware/UserAuthorization';
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
OneUptimeRequest,
|
||||
} from '../Utils/Express';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Response from '../Utils/Response';
|
||||
|
||||
export default class UserSMSAPI extends BaseAPI<UserSMS, UserSMSServiceType> {
|
||||
public constructor() {
|
||||
super(UserSMS, UserSMSService);
|
||||
|
||||
this.router.post(
|
||||
`/user-sms/verify`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body.itemId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
if (!req.body.code) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid code')
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the code matches and verify the phone number.
|
||||
const item: UserSMS | null = await this.service.findOneById({
|
||||
id: req.body['itemId'],
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
userId: true,
|
||||
verificationCode: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Item not found')
|
||||
);
|
||||
}
|
||||
|
||||
//cehck user id
|
||||
|
||||
if (
|
||||
item.userId?.toString() !==
|
||||
(
|
||||
req as OneUptimeRequest
|
||||
)?.userAuthorization?.userId?.toString()
|
||||
) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid user ID')
|
||||
);
|
||||
}
|
||||
|
||||
if (item.verificationCode !== req.body['code']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid code')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.updateOneById({
|
||||
id: item.id!,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
data: {
|
||||
isVerified: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
);
|
||||
|
||||
this.router.post(
|
||||
`/user-sms/resend-verification-code`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body.itemId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid item ID')
|
||||
);
|
||||
}
|
||||
|
||||
await this.service.resendVerificationCode(req.body.itemId);
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export const DatabasePort: Port = new Port(
|
||||
);
|
||||
|
||||
export const DatabaseUsername: string =
|
||||
process.env['DATABASE_USERNAME'] || 'oneuptimedbuser';
|
||||
process.env['DATABASE_USERNAME'] || 'postgres';
|
||||
|
||||
export const DatabasePassword: string =
|
||||
process.env['DATABASE_PASSWORD'] || 'password';
|
||||
@@ -66,6 +66,10 @@ export const WorkerHostname: Hostname = Hostname.fromString(
|
||||
process.env['WORKER_HOSTNAME'] || 'worker'
|
||||
);
|
||||
|
||||
export const LinkShortnerHostname: Route = new Route(
|
||||
process.env['LINK_SHORTNER_HOSTNAME'] || 'link-shortner'
|
||||
);
|
||||
|
||||
export const WorkflowHostname: Hostname = Hostname.fromString(
|
||||
process.env['WORKFLOW_HOSTNAME'] || 'workflow'
|
||||
);
|
||||
@@ -124,6 +128,10 @@ export const StatusPageRoute: Route = new Route(
|
||||
process.env['STATUS_PAGE_ROUTE'] || '/status-page'
|
||||
);
|
||||
|
||||
export const LinkShortnerRoute: Route = new Route(
|
||||
process.env['LINK_SHORTNER_ROUTE'] || '/l'
|
||||
);
|
||||
|
||||
export const DashboardRoute: Route = new Route(
|
||||
process.env['DASHBOARD_ROUTE'] || '/dashboard'
|
||||
);
|
||||
|
||||
71
CommonServer/Middleware/NotificationMiddleware.ts
Normal file
71
CommonServer/Middleware/NotificationMiddleware.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
NextFunction,
|
||||
OneUptimeRequest,
|
||||
} from '../Utils/Express';
|
||||
|
||||
import Response from '../Utils/Response';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import JSONFunctions from 'Common/Types/JSONFunctions';
|
||||
import JSONWebToken from '../Utils/JsonWebToken';
|
||||
import { OnCallInputRequest } from 'Common/Types/Call/CallRequest';
|
||||
import VoiceResponse from 'twilio/lib/twiml/VoiceResponse';
|
||||
|
||||
export default class NotificationMiddleware {
|
||||
public static async sendResponse(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
onCallInputRequest: OnCallInputRequest
|
||||
): Promise<void> {
|
||||
const response: VoiceResponse = new VoiceResponse();
|
||||
|
||||
if (onCallInputRequest[req.body['Digits']]) {
|
||||
response.say(onCallInputRequest[req.body['Digits']]!.sayMessage);
|
||||
} else {
|
||||
response.say(onCallInputRequest['default']!.sayMessage);
|
||||
}
|
||||
|
||||
return Response.sendXmlResponse(req, res, response.toString());
|
||||
}
|
||||
|
||||
public static async isValidCallNotificationRequest(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction
|
||||
): Promise<void> {
|
||||
req = req as OneUptimeRequest;
|
||||
|
||||
if (!req.body['Digits']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid input')
|
||||
);
|
||||
}
|
||||
|
||||
if (!req.query['token']) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid token')
|
||||
);
|
||||
}
|
||||
|
||||
const token: string = req.query['token'] as string;
|
||||
|
||||
try {
|
||||
(req as any).callTokenData = JSONFunctions.deserialize(
|
||||
JSONWebToken.decodeJsonPayload(token)
|
||||
);
|
||||
} catch (e) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException('Invalid token')
|
||||
);
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,8 @@ export default class UserMiddleware {
|
||||
if (tenantId) {
|
||||
oneuptimeRequest.tenantId = tenantId;
|
||||
|
||||
// check if the force sso for login is present and if it is, check if the sso token is present and if it is then allow, otherwise decline.
|
||||
// update last active of project
|
||||
await ProjectService.updateLastActive(tenantId);
|
||||
}
|
||||
|
||||
if (ProjectMiddleware.hasApiKey(req)) {
|
||||
|
||||
@@ -15,17 +15,20 @@ import Label from 'Model/Models/Label';
|
||||
import QueryHelper from '../Types/Database/QueryHelper';
|
||||
import APIKeyPermission from 'Model/Models/ApiKeyPermission';
|
||||
import ApiKeyPermissionService from './ApiKeyPermissionService';
|
||||
import BaseService from './BaseService';
|
||||
|
||||
enum PermissionNamespace {
|
||||
GlobalPermission = 'global-permissions',
|
||||
ProjectPermission = 'project-permissions',
|
||||
}
|
||||
|
||||
export default class AccessTokenService {
|
||||
public static async refreshUserAllPermissions(
|
||||
userId: ObjectID
|
||||
): Promise<void> {
|
||||
await AccessTokenService.refreshUserGlobalAccessPermission(userId);
|
||||
export class AccessTokenService extends BaseService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public async refreshUserAllPermissions(userId: ObjectID): Promise<void> {
|
||||
await this.refreshUserGlobalAccessPermission(userId);
|
||||
|
||||
// query for all projects user belongs to.
|
||||
const teamMembers: Array<TeamMember> = await TeamMemberService.findBy({
|
||||
@@ -54,14 +57,11 @@ export default class AccessTokenService {
|
||||
);
|
||||
|
||||
for (const projectId of projectIds) {
|
||||
await AccessTokenService.refreshUserTenantAccessPermission(
|
||||
userId,
|
||||
projectId
|
||||
);
|
||||
await this.refreshUserTenantAccessPermission(userId, projectId);
|
||||
}
|
||||
}
|
||||
|
||||
public static async getDefaultApiGlobalPermission(
|
||||
public async getDefaultApiGlobalPermission(
|
||||
projectId: ObjectID
|
||||
): Promise<UserGlobalAccessPermission> {
|
||||
return {
|
||||
@@ -75,7 +75,7 @@ export default class AccessTokenService {
|
||||
};
|
||||
}
|
||||
|
||||
public static async getApiTenantAccessPermission(
|
||||
public async getApiTenantAccessPermission(
|
||||
projectId: ObjectID,
|
||||
apiKeyId: ObjectID
|
||||
): Promise<UserTenantAccessPermission> {
|
||||
@@ -116,14 +116,14 @@ export default class AccessTokenService {
|
||||
}
|
||||
|
||||
const permission: UserTenantAccessPermission =
|
||||
AccessTokenService.getDefaultUserTenantAccessPermission(projectId);
|
||||
this.getDefaultUserTenantAccessPermission(projectId);
|
||||
|
||||
permission.permissions = permission.permissions.concat(userPermissions);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
public static async refreshUserGlobalAccessPermission(
|
||||
public async refreshUserGlobalAccessPermission(
|
||||
userId: ObjectID
|
||||
): Promise<UserGlobalAccessPermission> {
|
||||
// query for all projects user belongs to.
|
||||
@@ -163,7 +163,7 @@ export default class AccessTokenService {
|
||||
return permissionToStore;
|
||||
}
|
||||
|
||||
public static getDefaultUserTenantAccessPermission(
|
||||
public getDefaultUserTenantAccessPermission(
|
||||
projectId: ObjectID
|
||||
): UserTenantAccessPermission {
|
||||
const userPermissions: Array<UserPermission> = [];
|
||||
@@ -189,7 +189,7 @@ export default class AccessTokenService {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public static async getUserGlobalAccessPermission(
|
||||
public async getUserGlobalAccessPermission(
|
||||
userId: ObjectID
|
||||
): Promise<UserGlobalAccessPermission | null> {
|
||||
const json: JSONObject | null = await GlobalCache.getJSON(
|
||||
@@ -198,9 +198,7 @@ export default class AccessTokenService {
|
||||
);
|
||||
|
||||
if (!json) {
|
||||
return await AccessTokenService.refreshUserGlobalAccessPermission(
|
||||
userId
|
||||
);
|
||||
return await this.refreshUserGlobalAccessPermission(userId);
|
||||
}
|
||||
|
||||
const accessPermission: UserGlobalAccessPermission =
|
||||
@@ -211,7 +209,7 @@ export default class AccessTokenService {
|
||||
return accessPermission;
|
||||
}
|
||||
|
||||
public static async refreshUserTenantAccessPermission(
|
||||
public async refreshUserTenantAccessPermission(
|
||||
userId: ObjectID,
|
||||
projectId: ObjectID
|
||||
): Promise<UserTenantAccessPermission | null> {
|
||||
@@ -279,7 +277,7 @@ export default class AccessTokenService {
|
||||
}
|
||||
|
||||
const permission: UserTenantAccessPermission =
|
||||
AccessTokenService.getDefaultUserTenantAccessPermission(projectId);
|
||||
this.getDefaultUserTenantAccessPermission(projectId);
|
||||
|
||||
permission.permissions = permission.permissions.concat(userPermissions);
|
||||
|
||||
@@ -292,7 +290,7 @@ export default class AccessTokenService {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public static async getUserTenantAccessPermission(
|
||||
public async getUserTenantAccessPermission(
|
||||
userId: ObjectID,
|
||||
projectId: ObjectID
|
||||
): Promise<UserTenantAccessPermission | null> {
|
||||
@@ -307,7 +305,7 @@ export default class AccessTokenService {
|
||||
}
|
||||
|
||||
if (!json) {
|
||||
return await AccessTokenService.refreshUserTenantAccessPermission(
|
||||
return await this.refreshUserTenantAccessPermission(
|
||||
userId,
|
||||
projectId
|
||||
);
|
||||
@@ -316,3 +314,5 @@ export default class AccessTokenService {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
export default new AccessTokenService();
|
||||
|
||||
3
CommonServer/Services/BaseService.ts
Normal file
3
CommonServer/Services/BaseService.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default class BaseService {
|
||||
public constructor() {}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/BillingInvoice';
|
||||
import DatabaseService, { OnDelete, OnFind } from './DatabaseService';
|
||||
import DatabaseService, { OnFind } from './DatabaseService';
|
||||
import FindBy from '../Types/Database/FindBy';
|
||||
import ProjectService from './ProjectService';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import Project from 'Model/Models/Project';
|
||||
import BillingService, { Invoice } from './BillingService';
|
||||
import DeleteBy from '../Types/Database/DeleteBy';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
this.setDoNotAllowDelete(true);
|
||||
}
|
||||
|
||||
protected override async onBeforeFind(
|
||||
@@ -87,12 +87,6 @@ export class Service extends DatabaseService<Model> {
|
||||
|
||||
return { findBy, carryForward: invoices };
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
_deleteBy: DeleteBy<Model>
|
||||
): Promise<OnDelete<Model>> {
|
||||
throw new BadDataException('Invoice should not be deleted.');
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -10,6 +10,7 @@ import Stripe from 'stripe';
|
||||
import { BillingPrivateKey, IsBillingEnabled } from '../Config';
|
||||
import ServerMeteredPlan from '../Types/Billing/MeteredPlan/ServerMeteredPlan';
|
||||
import SubscriptionStatus from 'Common/Types/Billing/SubscriptionStatus';
|
||||
import BaseService from './BaseService';
|
||||
|
||||
export interface PaymentMethod {
|
||||
id: string;
|
||||
@@ -28,16 +29,17 @@ export interface Invoice {
|
||||
customerId: string | undefined;
|
||||
}
|
||||
|
||||
export class BillingService {
|
||||
private static stripe: Stripe = new Stripe(BillingPrivateKey, {
|
||||
export class BillingService extends BaseService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
private stripe: Stripe = new Stripe(BillingPrivateKey, {
|
||||
apiVersion: '2022-08-01',
|
||||
});
|
||||
|
||||
// returns billing id of the customer.
|
||||
public static async createCustomer(
|
||||
name: string,
|
||||
id: ObjectID
|
||||
): Promise<string> {
|
||||
public async createCustomer(name: string, id: ObjectID): Promise<string> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
@@ -55,7 +57,7 @@ export class BillingService {
|
||||
return customer.id;
|
||||
}
|
||||
|
||||
public static async updateCustomerName(
|
||||
public async updateCustomerName(
|
||||
id: string,
|
||||
newName: string
|
||||
): Promise<void> {
|
||||
@@ -68,7 +70,7 @@ export class BillingService {
|
||||
await this.stripe.customers.update(id, { name: newName });
|
||||
}
|
||||
|
||||
public static async deleteCustomer(id: string): Promise<void> {
|
||||
public async deleteCustomer(id: string): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
@@ -78,11 +80,11 @@ export class BillingService {
|
||||
await this.stripe.customers.del(id);
|
||||
}
|
||||
|
||||
public static isBillingEnabled(): boolean {
|
||||
public isBillingEnabled(): boolean {
|
||||
return IsBillingEnabled;
|
||||
}
|
||||
|
||||
public static async subscribeToPlan(
|
||||
public async subscribeToPlan(
|
||||
projectId: ObjectID,
|
||||
customerId: string,
|
||||
serverMeteredPlans: Array<typeof ServerMeteredPlan>,
|
||||
@@ -149,7 +151,7 @@ export class BillingService {
|
||||
};
|
||||
}
|
||||
|
||||
public static async changeQuantity(
|
||||
public async changeQuantity(
|
||||
subscriptionId: string,
|
||||
quantity: number
|
||||
): Promise<void> {
|
||||
@@ -183,7 +185,7 @@ export class BillingService {
|
||||
});
|
||||
}
|
||||
|
||||
public static async addOrUpdateMeteredPricingOnSubscription(
|
||||
public async addOrUpdateMeteredPricingOnSubscription(
|
||||
subscriptionId: string,
|
||||
meteredPlan: MeteredPlan,
|
||||
quantity: number,
|
||||
@@ -264,7 +266,7 @@ export class BillingService {
|
||||
// complete.
|
||||
}
|
||||
|
||||
public static async changePlan(
|
||||
public async changePlan(
|
||||
projectId: ObjectID,
|
||||
subscriptionId: string,
|
||||
serverMeteredPlans: Array<typeof ServerMeteredPlan>,
|
||||
@@ -324,7 +326,7 @@ export class BillingService {
|
||||
};
|
||||
}
|
||||
|
||||
public static async deletePaymentMethod(
|
||||
public async deletePaymentMethod(
|
||||
customerId: string,
|
||||
paymentMethodId: string
|
||||
): Promise<void> {
|
||||
@@ -346,9 +348,7 @@ export class BillingService {
|
||||
await this.stripe.paymentMethods.detach(paymentMethodId);
|
||||
}
|
||||
|
||||
public static async hasPaymentMethods(
|
||||
customerId: string
|
||||
): Promise<boolean> {
|
||||
public async hasPaymentMethods(customerId: string): Promise<boolean> {
|
||||
if ((await this.getPaymentMethods(customerId)).length > 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -356,7 +356,7 @@ export class BillingService {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async getPaymentMethods(
|
||||
public async getPaymentMethods(
|
||||
customerId: string
|
||||
): Promise<Array<PaymentMethod>> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
@@ -429,9 +429,7 @@ export class BillingService {
|
||||
return paymenMethods;
|
||||
}
|
||||
|
||||
public static async getSetupIntentSecret(
|
||||
customerId: string
|
||||
): Promise<string> {
|
||||
public async getSetupIntentSecret(customerId: string): Promise<string> {
|
||||
const setupIntent: Stripe.Response<Stripe.SetupIntent> =
|
||||
await this.stripe.setupIntents.create({
|
||||
customer: customerId,
|
||||
@@ -446,9 +444,7 @@ export class BillingService {
|
||||
return setupIntent.client_secret;
|
||||
}
|
||||
|
||||
public static async cancelSubscription(
|
||||
subscriptionId: string
|
||||
): Promise<void> {
|
||||
public async cancelSubscription(subscriptionId: string): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
@@ -461,7 +457,7 @@ export class BillingService {
|
||||
}
|
||||
}
|
||||
|
||||
public static async getSubscriptionStatus(
|
||||
public async getSubscriptionStatus(
|
||||
subscriptionId: string
|
||||
): Promise<SubscriptionStatus> {
|
||||
const subscription: Stripe.Subscription = await this.getSubscription(
|
||||
@@ -470,7 +466,7 @@ export class BillingService {
|
||||
return subscription.status as SubscriptionStatus;
|
||||
}
|
||||
|
||||
public static async getSubscription(
|
||||
public async getSubscription(
|
||||
subscriptionId: string
|
||||
): Promise<Stripe.Subscription> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
@@ -485,9 +481,7 @@ export class BillingService {
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public static async getInvoices(
|
||||
customerId: string
|
||||
): Promise<Array<Invoice>> {
|
||||
public async getInvoices(customerId: string): Promise<Array<Invoice>> {
|
||||
const invoices: Stripe.ApiList<Stripe.Invoice> =
|
||||
await this.stripe.invoices.list({
|
||||
customer: customerId,
|
||||
@@ -507,7 +501,7 @@ export class BillingService {
|
||||
});
|
||||
}
|
||||
|
||||
public static async genrateInvoiceAndChargeCustomer(
|
||||
public async genrateInvoiceAndChargeCustomer(
|
||||
customerId: string,
|
||||
itemText: string,
|
||||
amountInUsd: number
|
||||
@@ -540,9 +534,7 @@ export class BillingService {
|
||||
}
|
||||
}
|
||||
|
||||
public static async voidInvoice(
|
||||
invoiceId: string
|
||||
): Promise<Stripe.Invoice> {
|
||||
public async voidInvoice(invoiceId: string): Promise<Stripe.Invoice> {
|
||||
const invoice: Stripe.Invoice = await this.stripe.invoices.voidInvoice(
|
||||
invoiceId
|
||||
);
|
||||
@@ -550,7 +542,7 @@ export class BillingService {
|
||||
return invoice;
|
||||
}
|
||||
|
||||
public static async payInvoice(
|
||||
public async payInvoice(
|
||||
customerId: string,
|
||||
invoiceId: string
|
||||
): Promise<Invoice> {
|
||||
@@ -583,4 +575,4 @@ export class BillingService {
|
||||
}
|
||||
}
|
||||
|
||||
export default BillingService;
|
||||
export default new BillingService();
|
||||
|
||||
12
CommonServer/Services/CallLogService.ts
Normal file
12
CommonServer/Services/CallLogService.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/CallLog';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
this.hardDeleteItemsOlderThanInDays('createdAt', 30);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
52
CommonServer/Services/CallService.ts
Normal file
52
CommonServer/Services/CallService.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import EmptyResponseData from 'Common/Types/API/EmptyResponse';
|
||||
import HTTPResponse from 'Common/Types/API/HTTPResponse';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import API from 'Common/Utils/API';
|
||||
import { NotificationHostname } from '../Config';
|
||||
import Protocol from 'Common/Types/API/Protocol';
|
||||
import ClusterKeyAuthorization from '../Middleware/ClusterKeyAuthorization';
|
||||
import Phone from 'Common/Types/Phone';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import CallRequest from 'Common/Types/Call/CallRequest';
|
||||
import BaseService from './BaseService';
|
||||
|
||||
export class CallService extends BaseService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public async makeCall(
|
||||
callRequest: CallRequest,
|
||||
options: {
|
||||
projectId?: ObjectID | undefined; // project id for sms log
|
||||
from?: Phone; // from phone number
|
||||
isSensitive?: boolean; // if true, message will not be logged
|
||||
userOnCallLogTimelineId?: ObjectID;
|
||||
}
|
||||
): Promise<HTTPResponse<EmptyResponseData>> {
|
||||
const body: JSONObject = {
|
||||
callRequest: callRequest,
|
||||
from: options.from?.toString(),
|
||||
projectId: options.projectId?.toString(),
|
||||
isSensitive: options.isSensitive,
|
||||
userOnCallLogTimelineId:
|
||||
options.userOnCallLogTimelineId?.toString(),
|
||||
};
|
||||
|
||||
return await API.post<EmptyResponseData>(
|
||||
new URL(
|
||||
Protocol.HTTP,
|
||||
NotificationHostname,
|
||||
new Route('/call/make-call')
|
||||
),
|
||||
body,
|
||||
{
|
||||
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default new CallService();
|
||||
@@ -1,5 +1,5 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/GlobalConfig';
|
||||
import Model from 'Model/Models/DataMigration';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
@@ -7,5 +7,4 @@ export class Service extends DatabaseService<Model> {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
@@ -49,6 +49,9 @@ import Route from 'Common/Types/API/Route';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import ClusterKeyAuthorization from '../Middleware/ClusterKeyAuthorization';
|
||||
import Text from 'Common/Types/Text';
|
||||
import logger from '../Utils/Logger';
|
||||
import BaseService from './BaseService';
|
||||
import { getMaxLengthFromTableColumnType } from 'Common/Types/Database/ColumnLength';
|
||||
|
||||
export type DatabaseTriggerType = 'on-create' | 'on-update' | 'on-delete';
|
||||
|
||||
@@ -72,7 +75,7 @@ export interface OnUpdate<TBaseModel extends BaseModel> {
|
||||
carryForward: any;
|
||||
}
|
||||
|
||||
class DatabaseService<TBaseModel extends BaseModel> {
|
||||
class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
||||
private postgresDatabase!: PostgresDatabase;
|
||||
public entityType!: { new (): TBaseModel };
|
||||
private model!: TBaseModel;
|
||||
@@ -94,10 +97,13 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
this._hardDeleteItemsOlderThanDays = v;
|
||||
}
|
||||
|
||||
public doNotAllowDelete: boolean = false;
|
||||
|
||||
public constructor(
|
||||
modelType: { new (): TBaseModel },
|
||||
postgresDatabase?: PostgresDatabase
|
||||
) {
|
||||
super();
|
||||
this.entityType = modelType;
|
||||
this.model = new modelType();
|
||||
this.modelName = modelType.name;
|
||||
@@ -107,6 +113,10 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
}
|
||||
}
|
||||
|
||||
public setDoNotAllowDelete(doNotAllowDelete: boolean): void {
|
||||
this.doNotAllowDelete = doNotAllowDelete;
|
||||
}
|
||||
|
||||
public hardDeleteItemsOlderThanInDays(
|
||||
columnName: string,
|
||||
olderThan: number
|
||||
@@ -151,7 +161,21 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected checkRequiredFields(data: TBaseModel): void {
|
||||
protected generateDefaultValues(data: TBaseModel): TBaseModel {
|
||||
const tableColumns: Array<string> = data.getTableColumns().columns;
|
||||
|
||||
for (const column of tableColumns) {
|
||||
const metadata: TableColumnMetadata =
|
||||
data.getTableColumnMetadata(column);
|
||||
if (metadata.forceGetDefaultValueOnCreate) {
|
||||
(data as any)[column] = metadata.forceGetDefaultValueOnCreate();
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected checkRequiredFields(data: TBaseModel): TBaseModel {
|
||||
// Check required fields.
|
||||
|
||||
const relatationalColumns: Dictionary<string> = {};
|
||||
@@ -203,6 +227,8 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
throw new BadDataException(`${requiredField} is required`);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected async onBeforeCreate(
|
||||
@@ -411,6 +437,8 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
props: DatabaseCommonInteractionProps,
|
||||
isUpdate: boolean = false
|
||||
): Promise<TBaseModel | QueryDeepPartialEntity<TBaseModel>> {
|
||||
data = this.checkMaxLengthOfFields(data as TBaseModel);
|
||||
|
||||
const columns: Columns = this.model.getTableColumns();
|
||||
|
||||
for (const columnName of columns.columns) {
|
||||
@@ -505,25 +533,29 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
projectId: ObjectID,
|
||||
triggerType: DatabaseTriggerType
|
||||
): Promise<void> {
|
||||
await API.post(
|
||||
new URL(
|
||||
Protocol.HTTP,
|
||||
WorkflowHostname,
|
||||
new Route(
|
||||
`${WorkflowRoute.toString()}/model/${projectId.toString()}/${Text.pascalCaseToDashes(
|
||||
this.getModel().tableName!
|
||||
)}/${triggerType}`
|
||||
)
|
||||
),
|
||||
{
|
||||
data: {
|
||||
_id: id.toString(),
|
||||
if (this.getModel().enableWorkflowOn) {
|
||||
API.post(
|
||||
new URL(
|
||||
Protocol.HTTP,
|
||||
WorkflowHostname,
|
||||
new Route(
|
||||
`${WorkflowRoute.toString()}/model/${projectId.toString()}/${Text.pascalCaseToDashes(
|
||||
this.getModel().tableName!
|
||||
)}/${triggerType}`
|
||||
)
|
||||
),
|
||||
{
|
||||
data: {
|
||||
_id: id.toString(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
||||
}
|
||||
);
|
||||
{
|
||||
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
||||
}
|
||||
).catch((error: Error) => {
|
||||
logger.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async create(createBy: CreateBy<TBaseModel>): Promise<TBaseModel> {
|
||||
@@ -546,7 +578,8 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
data.setColumnValue(tenantColumnName, _createdBy.props.tenantId);
|
||||
}
|
||||
|
||||
this.checkRequiredFields(data);
|
||||
data = this.generateDefaultValues(data);
|
||||
data = this.checkRequiredFields(data);
|
||||
|
||||
if (!this.isValid(data)) {
|
||||
throw new BadDataException('Data is not valid');
|
||||
@@ -593,22 +626,22 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
}
|
||||
|
||||
// hit workflow.;
|
||||
if (
|
||||
this.getModel().enableWorkflowOn?.create &&
|
||||
(createBy.props.tenantId ||
|
||||
(this.getModel().getTenantColumn() &&
|
||||
createBy.data.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
)))
|
||||
) {
|
||||
await this.onTrigger(
|
||||
createBy.data.id!,
|
||||
createBy.props.tenantId ||
|
||||
createBy.data.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
),
|
||||
'on-create'
|
||||
);
|
||||
if (this.getModel().enableWorkflowOn?.create) {
|
||||
let tenantId: ObjectID | undefined = createBy.props.tenantId;
|
||||
|
||||
if (!tenantId && this.getModel().getTenantColumn()) {
|
||||
tenantId = createBy.data.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
);
|
||||
}
|
||||
|
||||
if (tenantId) {
|
||||
await this.onTrigger(
|
||||
createBy.data.id!,
|
||||
tenantId,
|
||||
'on-create'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return createBy.data;
|
||||
@@ -618,6 +651,38 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
}
|
||||
}
|
||||
|
||||
private checkMaxLengthOfFields<TBaseModel extends BaseModel>(
|
||||
data: TBaseModel
|
||||
): TBaseModel {
|
||||
// Check required fields.
|
||||
|
||||
const tableColumns: Array<string> =
|
||||
this.model.getTableColumns().columns;
|
||||
|
||||
for (const column of tableColumns) {
|
||||
const metadata: TableColumnMetadata =
|
||||
this.model.getTableColumnMetadata(column);
|
||||
if (
|
||||
(data as any)[column] &&
|
||||
metadata.type &&
|
||||
getMaxLengthFromTableColumnType(metadata.type)
|
||||
) {
|
||||
if (
|
||||
(data as any)[column].toString().length >
|
||||
getMaxLengthFromTableColumnType(metadata.type)!
|
||||
) {
|
||||
throw new BadDataException(
|
||||
`${column} length cannot be more than ${getMaxLengthFromTableColumnType(
|
||||
metadata.type
|
||||
)} characters`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private async checkTotalItemsBy(
|
||||
createdBy: CreateBy<TBaseModel>
|
||||
): Promise<void> {
|
||||
@@ -855,6 +920,10 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
|
||||
private async _deleteBy(deleteBy: DeleteBy<TBaseModel>): Promise<number> {
|
||||
try {
|
||||
if (this.doNotAllowDelete) {
|
||||
throw new BadDataException('Delete not allowed');
|
||||
}
|
||||
|
||||
const onDelete: OnDelete<TBaseModel> = deleteBy.props.ignoreHooks
|
||||
? { deleteBy, carryForward: [] }
|
||||
: await this.onBeforeDelete(deleteBy);
|
||||
@@ -930,21 +999,23 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
(deleteBy.props.tenantId || this.getModel().getTenantColumn())
|
||||
) {
|
||||
for (const item of items) {
|
||||
if (
|
||||
(this.getModel().getTenantColumn() &&
|
||||
item.getValue<ObjectID>(
|
||||
if (this.getModel().enableWorkflowOn?.create) {
|
||||
let tenantId: ObjectID | undefined =
|
||||
deleteBy.props.tenantId;
|
||||
|
||||
if (!tenantId && this.getModel().getTenantColumn()) {
|
||||
tenantId = item.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
)) ||
|
||||
deleteBy.props.tenantId
|
||||
) {
|
||||
await this.onTrigger(
|
||||
item.id!,
|
||||
deleteBy.props.tenantId ||
|
||||
item.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
),
|
||||
'on-delete'
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
if (tenantId) {
|
||||
await this.onTrigger(
|
||||
item.id!,
|
||||
tenantId,
|
||||
'on-delete'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -976,15 +1047,27 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
withDeleted?: boolean | undefined
|
||||
): Promise<Array<TBaseModel>> {
|
||||
try {
|
||||
let automaticallyAddedCreatedAtInSelect: boolean = false;
|
||||
|
||||
if (!findBy.sort || Object.keys(findBy.sort).length === 0) {
|
||||
findBy.sort = {
|
||||
createdAt: SortOrder.Descending,
|
||||
};
|
||||
|
||||
if (!findBy.select) {
|
||||
findBy.select = {} as any;
|
||||
}
|
||||
|
||||
if (!(findBy.select as any)['createdAt']) {
|
||||
(findBy.select as any)['createdAt'] = true;
|
||||
automaticallyAddedCreatedAtInSelect = true;
|
||||
}
|
||||
}
|
||||
|
||||
const onFind: OnFind<TBaseModel> = findBy.props.ignoreHooks
|
||||
? { findBy, carryForward: [] }
|
||||
: await this.onBeforeFind(findBy);
|
||||
const onBeforeFind: FindBy<TBaseModel> = onFind.findBy;
|
||||
const onBeforeFind: FindBy<TBaseModel> = { ...onFind.findBy };
|
||||
const carryForward: any = onFind.carryForward;
|
||||
|
||||
if (
|
||||
@@ -998,10 +1081,6 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
(onBeforeFind.select as any)['_id'] = true;
|
||||
}
|
||||
|
||||
if (!(onBeforeFind.select as any)['createdAt']) {
|
||||
(onBeforeFind.select as any)['createdAt'] = true;
|
||||
}
|
||||
|
||||
const result: {
|
||||
query: Query<TBaseModel>;
|
||||
select: Select<TBaseModel> | null;
|
||||
@@ -1044,6 +1123,13 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
decryptedItems,
|
||||
onBeforeFind
|
||||
);
|
||||
|
||||
for (const item of decryptedItems) {
|
||||
if (automaticallyAddedCreatedAtInSelect) {
|
||||
delete (item as any).createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
if (!findBy.props.ignoreHooks) {
|
||||
decryptedItems = await (
|
||||
await this.onFindSuccess(
|
||||
@@ -1141,6 +1227,10 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
public async findOneById(
|
||||
findOneById: FindOneByID<TBaseModel>
|
||||
): Promise<TBaseModel | null> {
|
||||
if (!findOneById.id) {
|
||||
throw new BadDataException('findOneById.id is required');
|
||||
}
|
||||
|
||||
return await this.findOneBy({
|
||||
query: {
|
||||
_id: findOneById.id.toString() as any,
|
||||
@@ -1205,22 +1295,19 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
await this.getRepository().save(updatedItem);
|
||||
|
||||
// hit workflow.
|
||||
if (
|
||||
(this.getModel().enableWorkflowOn?.update &&
|
||||
updateBy.props.tenantId) ||
|
||||
(this.getModel().getTenantColumn() &&
|
||||
item.getValue<ObjectID>(
|
||||
if (this.getModel().enableWorkflowOn?.update) {
|
||||
let tenantId: ObjectID | undefined =
|
||||
updateBy.props.tenantId;
|
||||
|
||||
if (!tenantId && this.getModel().getTenantColumn()) {
|
||||
tenantId = item.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
))
|
||||
) {
|
||||
await this.onTrigger(
|
||||
item.id!,
|
||||
updateBy.props.tenantId ||
|
||||
item.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
),
|
||||
'on-update'
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
if (tenantId) {
|
||||
await this.onTrigger(item.id!, tenantId, 'on-update');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1264,6 +1351,10 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
public async updateOneById(
|
||||
updateById: UpdateByID<TBaseModel>
|
||||
): Promise<void> {
|
||||
if (!updateById.id) {
|
||||
throw new BadDataException('updateById.id is required');
|
||||
}
|
||||
|
||||
await this.updateOneBy({
|
||||
query: {
|
||||
_id: updateById.id.toString() as any,
|
||||
|
||||
@@ -5,6 +5,8 @@ import DatabaseService from './DatabaseService';
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
this.hardDeleteItemsOlderThanInDays('createdAt', 30);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/Incident';
|
||||
import DatabaseService, { OnCreate } from './DatabaseService';
|
||||
import DatabaseService, { OnCreate, OnUpdate } from './DatabaseService';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import Monitor from 'Model/Models/Monitor';
|
||||
import MonitorService from './MonitorService';
|
||||
@@ -21,12 +21,70 @@ import URL from 'Common/Types/API/URL';
|
||||
import User from 'Model/Models/User';
|
||||
import TeamMemberService from './TeamMemberService';
|
||||
import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
|
||||
import UserService from './UserService';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import OnCallDutyPolicyService from './OnCallDutyPolicyService';
|
||||
import UserNotificationEventType from 'Common/Types/UserNotification/UserNotificationEventType';
|
||||
import SortOrder from 'Common/Types/Database/SortOrder';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
|
||||
public async acknowledgeIncident(
|
||||
incidentId: ObjectID,
|
||||
acknowledgedByUserId: ObjectID
|
||||
): Promise<void> {
|
||||
const incident: Model | null = await this.findOneById({
|
||||
id: incidentId,
|
||||
select: {
|
||||
projectId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!incident || !incident.projectId) {
|
||||
throw new BadDataException('Incident not found.');
|
||||
}
|
||||
|
||||
const incidentState: IncidentState | null =
|
||||
await IncidentStateService.findOneBy({
|
||||
query: {
|
||||
projectId: incident.projectId,
|
||||
isAcknowledgedState: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!incidentState || !incidentState.id) {
|
||||
throw new BadDataException(
|
||||
'Acknowledged state not found for this project. Please add acknowledged state from settings.'
|
||||
);
|
||||
}
|
||||
|
||||
const incidentStateTimeline: IncidentStateTimeline =
|
||||
new IncidentStateTimeline();
|
||||
incidentStateTimeline.projectId = incident.projectId;
|
||||
incidentStateTimeline.incidentId = incidentId;
|
||||
incidentStateTimeline.incidentStateId = incidentState.id;
|
||||
incidentStateTimeline.createdByUserId = acknowledgedByUserId;
|
||||
|
||||
await IncidentStateTimelineService.create({
|
||||
data: incidentStateTimeline,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<Model>
|
||||
): Promise<OnCreate<Model>> {
|
||||
@@ -59,6 +117,41 @@ export class Service extends DatabaseService<Model> {
|
||||
|
||||
createBy.data.currentIncidentStateId = incidentState.id;
|
||||
|
||||
if (
|
||||
(createBy.data.createdByUserId ||
|
||||
createBy.data.createdByUser ||
|
||||
createBy.props.userId) &&
|
||||
!createBy.data.rootCause
|
||||
) {
|
||||
let userId: ObjectID | undefined = createBy.data.createdByUserId;
|
||||
|
||||
if (createBy.props.userId) {
|
||||
userId = createBy.props.userId;
|
||||
}
|
||||
|
||||
if (createBy.data.createdByUser && createBy.data.createdByUser.id) {
|
||||
userId = createBy.data.createdByUser.id;
|
||||
}
|
||||
|
||||
const user: User | null = await UserService.findOneBy({
|
||||
query: {
|
||||
_id: userId?.toString()!,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user) {
|
||||
createBy.data.rootCause = `Incident created by ${user.name} (${user.email})`;
|
||||
}
|
||||
}
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
}
|
||||
|
||||
@@ -87,6 +180,11 @@ export class Service extends DatabaseService<Model> {
|
||||
}) || [],
|
||||
createdItem.changeMonitorStatusToId,
|
||||
true, // notifyMonitorOwners
|
||||
createdItem.rootCause ||
|
||||
'Status was changed because incident ' +
|
||||
createdItem.id.toString() +
|
||||
' was created.',
|
||||
createdItem.createdStateLog,
|
||||
onCreate.createBy.props
|
||||
);
|
||||
}
|
||||
@@ -97,6 +195,8 @@ export class Service extends DatabaseService<Model> {
|
||||
createdItem.currentIncidentStateId,
|
||||
false,
|
||||
false,
|
||||
createdItem.rootCause,
|
||||
createdItem.createdStateLog,
|
||||
{
|
||||
isRoot: true,
|
||||
}
|
||||
@@ -123,6 +223,22 @@ export class Service extends DatabaseService<Model> {
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
createdItem.onCallDutyPolicies?.length &&
|
||||
createdItem.onCallDutyPolicies?.length > 0
|
||||
) {
|
||||
for (const policy of createdItem.onCallDutyPolicies) {
|
||||
await OnCallDutyPolicyService.executePolicy(
|
||||
new ObjectID(policy._id as string),
|
||||
{
|
||||
triggeredByIncidentId: createdItem.id!,
|
||||
userNotificationEventType:
|
||||
UserNotificationEventType.IncidentCreated,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
@@ -248,14 +364,71 @@ export class Service extends DatabaseService<Model> {
|
||||
);
|
||||
}
|
||||
|
||||
protected override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
updatedItemIds: ObjectID[]
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (
|
||||
onUpdate.updateBy.data.currentIncidentStateId &&
|
||||
onUpdate.updateBy.props.tenantId
|
||||
) {
|
||||
for (const itemId of updatedItemIds) {
|
||||
await this.changeIncidentState(
|
||||
onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
itemId,
|
||||
onUpdate.updateBy.data.currentIncidentStateId as ObjectID,
|
||||
true,
|
||||
true, // notifyOwners = true
|
||||
'This status was changed when the incident was updated.',
|
||||
undefined,
|
||||
{
|
||||
isRoot: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
|
||||
public async changeIncidentState(
|
||||
projectId: ObjectID,
|
||||
incidentId: ObjectID,
|
||||
incidentStateId: ObjectID,
|
||||
notifyStatusPageSubscribers: boolean,
|
||||
notifyOwners: boolean,
|
||||
props: DatabaseCommonInteractionProps
|
||||
rootCause: string | undefined,
|
||||
stateChangeLog: JSONObject | undefined,
|
||||
props: DatabaseCommonInteractionProps | undefined
|
||||
): Promise<void> {
|
||||
// get last monitor status timeline.
|
||||
const lastIncidentStatusTimeline: IncidentStateTimeline | null =
|
||||
await IncidentStateTimelineService.findOneBy({
|
||||
query: {
|
||||
incidentId: incidentId,
|
||||
projectId: projectId,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
incidentStateId: true,
|
||||
},
|
||||
sort: {
|
||||
createdAt: SortOrder.Descending,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
lastIncidentStatusTimeline &&
|
||||
lastIncidentStatusTimeline.incidentStateId &&
|
||||
lastIncidentStatusTimeline.incidentStateId.toString() ===
|
||||
incidentStateId.toString()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const statusTimeline: IncidentStateTimeline =
|
||||
new IncidentStateTimeline();
|
||||
|
||||
@@ -266,9 +439,16 @@ export class Service extends DatabaseService<Model> {
|
||||
statusTimeline.isStatusPageSubscribersNotified =
|
||||
!notifyStatusPageSubscribers;
|
||||
|
||||
if (stateChangeLog) {
|
||||
statusTimeline.stateChangeLog = stateChangeLog;
|
||||
}
|
||||
if (rootCause) {
|
||||
statusTimeline.rootCause = rootCause;
|
||||
}
|
||||
|
||||
await IncidentStateTimelineService.create({
|
||||
data: statusTimeline,
|
||||
props: props,
|
||||
props: props || {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,82 @@ import MonitorStatusService from './MonitorStatusService';
|
||||
import MonitorStatus from 'Model/Models/MonitorStatus';
|
||||
import MonitorStatusTimeline from 'Model/Models/MonitorStatusTimeline';
|
||||
import MonitorStatusTimelineService from './MonitorStatusTimelineService';
|
||||
import CreateBy from '../Types/Database/CreateBy';
|
||||
import UserService from './UserService';
|
||||
import User from 'Model/Models/User';
|
||||
|
||||
export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(IncidentStateTimeline, postgresDatabase);
|
||||
}
|
||||
|
||||
public async getResolvedStateIdForProject(
|
||||
projectId: ObjectID
|
||||
): Promise<ObjectID> {
|
||||
const resolvedState: IncidentState | null =
|
||||
await IncidentStateService.findOneBy({
|
||||
query: {
|
||||
projectId: projectId,
|
||||
isResolvedState: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!resolvedState) {
|
||||
throw new BadDataException(
|
||||
'No resolved state found for the project'
|
||||
);
|
||||
}
|
||||
|
||||
return resolvedState.id!;
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<MonitorStatusTimeline>
|
||||
): Promise<OnCreate<MonitorStatusTimeline>> {
|
||||
if (
|
||||
(createBy.data.createdByUserId ||
|
||||
createBy.data.createdByUser ||
|
||||
createBy.props.userId) &&
|
||||
!createBy.data.rootCause
|
||||
) {
|
||||
let userId: ObjectID | undefined = createBy.data.createdByUserId;
|
||||
|
||||
if (createBy.props.userId) {
|
||||
userId = createBy.props.userId;
|
||||
}
|
||||
|
||||
if (createBy.data.createdByUser && createBy.data.createdByUser.id) {
|
||||
userId = createBy.data.createdByUser.id;
|
||||
}
|
||||
|
||||
const user: User | null = await UserService.findOneBy({
|
||||
query: {
|
||||
_id: userId?.toString()!,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user) {
|
||||
createBy.data.rootCause = `Incident state created by ${user.name} (${user.email})`;
|
||||
}
|
||||
}
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
onCreate: OnCreate<IncidentStateTimeline>,
|
||||
createdItem: IncidentStateTimeline
|
||||
@@ -95,6 +165,35 @@ export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
|
||||
if (resolvedMonitorState) {
|
||||
for (const monitor of incident.monitors) {
|
||||
//check state of the monitor.
|
||||
|
||||
const latestState: MonitorStatusTimeline | null =
|
||||
await MonitorStatusTimelineService.findOneBy({
|
||||
query: {
|
||||
monitorId: monitor.id!,
|
||||
projectId: incident.projectId!,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
monitorStatusId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
sort: {
|
||||
createdAt: SortOrder.Descending,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
latestState &&
|
||||
latestState.monitorStatusId?.toString() ===
|
||||
resolvedMonitorState.id!.toString()
|
||||
) {
|
||||
// already on this state. Skip.
|
||||
continue;
|
||||
}
|
||||
|
||||
const monitorStatusTimeline: MonitorStatusTimeline =
|
||||
new MonitorStatusTimeline();
|
||||
monitorStatusTimeline.monitorId = monitor.id!;
|
||||
|
||||
@@ -27,7 +27,7 @@ import StatusPageHeaderLinkService from './StatusPageHeaderLinkService';
|
||||
import StatusPagePrivateUserService from './StatusPagePrivateUserService';
|
||||
|
||||
// On Call Duty
|
||||
import OnCallDutyService from './OnCallDutyService';
|
||||
import OnCallDutyPolicyService from './OnCallDutyPolicyService';
|
||||
|
||||
// Monitors
|
||||
import MonitorService from './MonitorService';
|
||||
@@ -70,57 +70,151 @@ import WorkflowLogService from './WorkflowLogService';
|
||||
|
||||
// SMS Log Servce
|
||||
import SmsLogService from './SmsLogService';
|
||||
import CallLogService from './CallLogService';
|
||||
import EmailLogService from './EmailLogService';
|
||||
import BillingService from './BillingService';
|
||||
import AccessTokenService from './AccessTokenService';
|
||||
import CallService from './CallService';
|
||||
import DataMigrationService from './DataMigrationService';
|
||||
import IncidentCustomFieldService from './IncidentCustomFieldService';
|
||||
import IncidentOwnerTeamService from './IncidentOwnerTeamService';
|
||||
import IncidentOwnerUserService from './IncidentOwnerUserService';
|
||||
import MailService from './MailService';
|
||||
import MonitorCustomFieldService from './MonitorCustomFieldService';
|
||||
import MonitorOwnerTeamService from './MonitorOwnerTeamService';
|
||||
import MonitorOwnerUserService from './MonitorOwnerUserService';
|
||||
import MonitorProbeService from './MonitorProbeService';
|
||||
import NotificationService from './NotificationService';
|
||||
import OnCallDutyPolicyCustomFieldService from './OnCallDutyPolicyCustomFieldService';
|
||||
import OnCallDutyPolicyEscalationRuleService from './OnCallDutyPolicyEscalationRuleService';
|
||||
import OnCallDutyPolicyEscalationRuleTeamService from './OnCallDutyPolicyEscalationRuleTeamService';
|
||||
import OnCallDutyPolicyEscalationRuleUserService from './OnCallDutyPolicyEscalationRuleUserService';
|
||||
import OnCallDutyPolicyExecutionLogService from './OnCallDutyPolicyExecutionLogService';
|
||||
import OnCallDutyPolicyExecutionLogTimelineService from './OnCallDutyPolicyExecutionLogTimelineService';
|
||||
import ProjectSsoService from './ProjectSsoService';
|
||||
import ScheduledMaintenanceCustomFieldService from './ScheduledMaintenanceCustomFieldService';
|
||||
import ScheduledMaintenanceOwnerTeamService from './ScheduledMaintenanceOwnerTeamService';
|
||||
import ScheduledMaintenanceOwnerUserService from './ScheduledMaintenanceOwnerUserService';
|
||||
import ShortLinkService from './ShortLinkService';
|
||||
import SmsService from './SmsService';
|
||||
import StatusPageCertificateService from './StatusPageCertificateService';
|
||||
import StatusPageCustomFieldService from './StatusPageCustomFieldService';
|
||||
import StatusPageOwnerTeamService from './StatusPageOwnerTeamService';
|
||||
import StatusPageOwnerUserService from './StatusPageOwnerUserService';
|
||||
import StatusPageSsoService from './StatusPageSsoService';
|
||||
import UserCallService from './UserCallService';
|
||||
import UserEmailService from './UserEmailService';
|
||||
import UserSmsService from './UserSmsService';
|
||||
import UserNotificationRuleService from './UserNotificationRuleService';
|
||||
import UserNotificationSettingService from './UserNotificationSettingService';
|
||||
import UserOnCallLogService from './UserOnCallLogService';
|
||||
import UserOnCallLogTimelineService from './UserOnCallLogTimelineService';
|
||||
import BaseService from './BaseService';
|
||||
|
||||
export default [
|
||||
UserService,
|
||||
ProbeService,
|
||||
ProjectService,
|
||||
EmailVerificationTokenService,
|
||||
TeamService,
|
||||
TeamMemberService,
|
||||
TeamPermissionService,
|
||||
ApiKeyService,
|
||||
LabelService,
|
||||
const services: Array<BaseService> = [
|
||||
// Import all services in current folder here.
|
||||
AccessTokenService,
|
||||
ApiKeyPermissionService,
|
||||
ProjectSmtpConfigService,
|
||||
StatusPageService,
|
||||
OnCallDutyService,
|
||||
MonitorService,
|
||||
MonitorStatusService,
|
||||
IncidentStateService,
|
||||
IncidentService,
|
||||
IncidentStateTimelineService,
|
||||
MonitorStatusTimelineService,
|
||||
IncidentPublicNoteService,
|
||||
IncidentInternalNoteService,
|
||||
FileService,
|
||||
ApiKeyService,
|
||||
|
||||
BillingInvoiceService,
|
||||
BillingPaymentMethodsService,
|
||||
BillingService,
|
||||
|
||||
CallLogService,
|
||||
CallService,
|
||||
|
||||
DataMigrationService,
|
||||
DomainService,
|
||||
|
||||
StatusPageGroupService,
|
||||
StatusPageDomainService,
|
||||
StatusPageResourceService,
|
||||
IncidentSeverityService,
|
||||
StatusPageAnnouncementService,
|
||||
StatusPageSubscriberService,
|
||||
StatusPageFooterLinkService,
|
||||
StatusPageHeaderLinkService,
|
||||
StatusPagePrivateUserService,
|
||||
EmailLogService,
|
||||
EmailVerificationTokenService,
|
||||
|
||||
ScheduledMaintenanceStateService,
|
||||
ScheduledMaintenanceService,
|
||||
ScheduledMaintenanceStateTimelineService,
|
||||
ScheduledMaintenancePublicNoteService,
|
||||
ScheduledMaintenanceInternalNoteService,
|
||||
FileService,
|
||||
|
||||
BillingPaymentMethodsService,
|
||||
BillingInvoiceService,
|
||||
|
||||
GreenlockChallengeService,
|
||||
GreenlockCertificateService,
|
||||
GreenlockChallengeService,
|
||||
|
||||
IncidentCustomFieldService,
|
||||
IncidentInternalNoteService,
|
||||
IncidentOwnerTeamService,
|
||||
IncidentOwnerUserService,
|
||||
IncidentPublicNoteService,
|
||||
IncidentService,
|
||||
IncidentSeverityService,
|
||||
IncidentStateService,
|
||||
IncidentStateTimelineService,
|
||||
|
||||
LabelService,
|
||||
|
||||
MailService,
|
||||
MonitorCustomFieldService,
|
||||
MonitorOwnerTeamService,
|
||||
MonitorOwnerUserService,
|
||||
MonitorProbeService,
|
||||
MonitorService,
|
||||
MonitorStatusService,
|
||||
MonitorStatusTimelineService,
|
||||
|
||||
NotificationService,
|
||||
|
||||
OnCallDutyPolicyCustomFieldService,
|
||||
OnCallDutyPolicyEscalationRuleService,
|
||||
OnCallDutyPolicyEscalationRuleTeamService,
|
||||
OnCallDutyPolicyEscalationRuleUserService,
|
||||
OnCallDutyPolicyExecutionLogService,
|
||||
OnCallDutyPolicyExecutionLogTimelineService,
|
||||
OnCallDutyPolicyService,
|
||||
|
||||
ProjectService,
|
||||
ProjectSmtpConfigService,
|
||||
ProbeService,
|
||||
ProjectSsoService,
|
||||
|
||||
ScheduledMaintenanceCustomFieldService,
|
||||
ScheduledMaintenanceInternalNoteService,
|
||||
ScheduledMaintenanceOwnerTeamService,
|
||||
ScheduledMaintenanceOwnerUserService,
|
||||
ScheduledMaintenancePublicNoteService,
|
||||
ScheduledMaintenanceService,
|
||||
ScheduledMaintenanceStateService,
|
||||
ScheduledMaintenanceStateTimelineService,
|
||||
|
||||
ShortLinkService,
|
||||
SmsLogService,
|
||||
SmsService,
|
||||
|
||||
StatusPageAnnouncementService,
|
||||
StatusPageCertificateService,
|
||||
StatusPageCustomFieldService,
|
||||
StatusPageDomainService,
|
||||
StatusPageFooterLinkService,
|
||||
StatusPageGroupService,
|
||||
StatusPageHeaderLinkService,
|
||||
StatusPageOwnerTeamService,
|
||||
StatusPageOwnerUserService,
|
||||
StatusPagePrivateUserService,
|
||||
StatusPageResourceService,
|
||||
StatusPageService,
|
||||
StatusPageSsoService,
|
||||
StatusPageSubscriberService,
|
||||
|
||||
TeamMemberService,
|
||||
TeamPermissionService,
|
||||
TeamService,
|
||||
|
||||
UserService,
|
||||
UserCallService,
|
||||
UserEmailService,
|
||||
UserNotificationRuleService,
|
||||
UserNotificationSettingService,
|
||||
UserOnCallLogService,
|
||||
UserOnCallLogTimelineService,
|
||||
UserSmsService,
|
||||
|
||||
WorkflowLogService,
|
||||
WorkflowService,
|
||||
WorkflowVariablesService,
|
||||
WorkflowLogService,
|
||||
|
||||
SmsLogService,
|
||||
];
|
||||
|
||||
export default services;
|
||||
|
||||
@@ -9,25 +9,41 @@ import Email from 'Common/Types/Email/EmailMessage';
|
||||
import EmailServer from 'Common/Types/Email/EmailServer';
|
||||
import Protocol from 'Common/Types/API/Protocol';
|
||||
import ClusterKeyAuthorization from '../Middleware/ClusterKeyAuthorization';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import BaseService from './BaseService';
|
||||
|
||||
export default class MailService {
|
||||
public static async sendMail(
|
||||
export class MailService extends BaseService {
|
||||
public async sendMail(
|
||||
mail: Email,
|
||||
mailServer?: EmailServer
|
||||
options?: {
|
||||
mailServer?: EmailServer | undefined;
|
||||
userOnCallLogTimelineId?: ObjectID;
|
||||
projectId?: ObjectID | undefined;
|
||||
}
|
||||
): Promise<HTTPResponse<EmptyResponseData>> {
|
||||
const body: JSONObject = {
|
||||
...mail,
|
||||
toEmail: mail.toEmail.toString(),
|
||||
};
|
||||
|
||||
if (mailServer) {
|
||||
body['SMTP_USERNAME'] = mailServer.username;
|
||||
body['SMTP_EMAIL'] = mailServer.fromEmail.toString();
|
||||
body['SMTP_FROM_NAME'] = mailServer.fromName;
|
||||
body['SMTP_IS_SECURE'] = mailServer.secure;
|
||||
body['SMTP_PORT'] = mailServer.port.toNumber();
|
||||
body['SMTP_HOST'] = mailServer.host.toString();
|
||||
body['SMTP_PASSWORD'] = mailServer.password;
|
||||
if (options && options.mailServer) {
|
||||
body['SMTP_ID'] = options.mailServer.id?.toString();
|
||||
body['SMTP_USERNAME'] = options.mailServer.username;
|
||||
body['SMTP_EMAIL'] = options.mailServer.fromEmail.toString();
|
||||
body['SMTP_FROM_NAME'] = options.mailServer.fromName;
|
||||
body['SMTP_IS_SECURE'] = options.mailServer.secure;
|
||||
body['SMTP_PORT'] = options.mailServer.port.toNumber();
|
||||
body['SMTP_HOST'] = options.mailServer.host.toString();
|
||||
body['SMTP_PASSWORD'] = options.mailServer.password;
|
||||
}
|
||||
|
||||
if (options?.userOnCallLogTimelineId) {
|
||||
body['userOnCallLogTimelineId'] =
|
||||
options.userOnCallLogTimelineId.toString();
|
||||
}
|
||||
|
||||
if (options?.projectId) {
|
||||
body['projectId'] = options.projectId.toString();
|
||||
}
|
||||
|
||||
return await API.post<EmptyResponseData>(
|
||||
@@ -43,3 +59,5 @@ export default class MailService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default new MailService();
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/Monitor';
|
||||
import DatabaseService, { OnCreate, OnDelete } from './DatabaseService';
|
||||
import DatabaseService, {
|
||||
OnCreate,
|
||||
OnDelete,
|
||||
OnUpdate,
|
||||
} from './DatabaseService';
|
||||
import CreateBy from '../Types/Database/CreateBy';
|
||||
import MonitorStatus from 'Model/Models/MonitorStatus';
|
||||
import MonitorStatusService from './MonitorStatusService';
|
||||
@@ -25,6 +29,8 @@ import Typeof from 'Common/Types/Typeof';
|
||||
import TeamMemberService from './TeamMemberService';
|
||||
import User from 'Model/Models/User';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import SortOrder from 'Common/Types/Database/SortOrder';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
@@ -44,9 +50,49 @@ export class Service extends DatabaseService<Model> {
|
||||
return onDelete;
|
||||
}
|
||||
|
||||
protected override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
updatedItemIds: ObjectID[]
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (
|
||||
onUpdate.updateBy.data.currentMonitorStatusId &&
|
||||
onUpdate.updateBy.props.tenantId
|
||||
) {
|
||||
await this.changeMonitorStatus(
|
||||
onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
updatedItemIds as Array<ObjectID>,
|
||||
onUpdate.updateBy.data.currentMonitorStatusId as ObjectID,
|
||||
true, // notifyOwners = true
|
||||
'This status was changed when the monitor was updated.',
|
||||
undefined,
|
||||
{
|
||||
isRoot: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<Model>
|
||||
): Promise<OnCreate<Model>> {
|
||||
if (!createBy.data.monitorType) {
|
||||
throw new BadDataException(
|
||||
'Monitor type required to create monitor.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!Object.values(MonitorType).includes(createBy.data.monitorType)) {
|
||||
throw new BadDataException(
|
||||
`Invalid monitor type "${
|
||||
createBy.data.monitorType
|
||||
}". Valid monitor types are ${Object.values(MonitorType).join(
|
||||
', '
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
|
||||
if (!createBy.props.tenantId) {
|
||||
throw new BadDataException('ProjectId required to create monitor.');
|
||||
}
|
||||
@@ -97,6 +143,8 @@ export class Service extends DatabaseService<Model> {
|
||||
[createdItem.id],
|
||||
createdItem.currentMonitorStatusId,
|
||||
false, // notifyOwners = false
|
||||
'This status was created when the monitor was created.',
|
||||
undefined,
|
||||
onCreate.createBy.props
|
||||
);
|
||||
|
||||
@@ -325,9 +373,39 @@ export class Service extends DatabaseService<Model> {
|
||||
monitorIds: Array<ObjectID>,
|
||||
monitorStatusId: ObjectID,
|
||||
notifyOwners: boolean,
|
||||
rootCause: string | undefined,
|
||||
statusChangeLog: JSONObject | undefined,
|
||||
props: DatabaseCommonInteractionProps
|
||||
): Promise<void> {
|
||||
for (const monitorId of monitorIds) {
|
||||
// get last monitor status timeline.
|
||||
const lastMonitorStatusTimeline: MonitorStatusTimeline | null =
|
||||
await MonitorStatusTimelineService.findOneBy({
|
||||
query: {
|
||||
monitorId: monitorId,
|
||||
projectId: projectId,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
monitorStatusId: true,
|
||||
},
|
||||
sort: {
|
||||
createdAt: SortOrder.Descending,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
lastMonitorStatusTimeline &&
|
||||
lastMonitorStatusTimeline.monitorStatusId &&
|
||||
lastMonitorStatusTimeline.monitorStatusId.toString() ===
|
||||
monitorStatusId.toString()
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const statusTimeline: MonitorStatusTimeline =
|
||||
new MonitorStatusTimeline();
|
||||
|
||||
@@ -336,6 +414,13 @@ export class Service extends DatabaseService<Model> {
|
||||
statusTimeline.projectId = projectId;
|
||||
statusTimeline.isOwnerNotified = !notifyOwners;
|
||||
|
||||
if (statusChangeLog) {
|
||||
statusTimeline.statusChangeLog = statusChangeLog;
|
||||
}
|
||||
if (rootCause) {
|
||||
statusTimeline.rootCause = rootCause;
|
||||
}
|
||||
|
||||
await MonitorStatusTimelineService.create({
|
||||
data: statusTimeline,
|
||||
props: props,
|
||||
|
||||
@@ -7,12 +7,56 @@ import MonitorStatusTimeline from 'Model/Models/MonitorStatusTimeline';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import SortOrder from 'Common/Types/Database/SortOrder';
|
||||
import PositiveNumber from 'Common/Types/PositiveNumber';
|
||||
import CreateBy from '../Types/Database/CreateBy';
|
||||
import UserService from './UserService';
|
||||
import User from 'Model/Models/User';
|
||||
|
||||
export class Service extends DatabaseService<MonitorStatusTimeline> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(MonitorStatusTimeline, postgresDatabase);
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<MonitorStatusTimeline>
|
||||
): Promise<OnCreate<MonitorStatusTimeline>> {
|
||||
if (
|
||||
(createBy.data.createdByUserId ||
|
||||
createBy.data.createdByUser ||
|
||||
createBy.props.userId) &&
|
||||
!createBy.data.rootCause
|
||||
) {
|
||||
let userId: ObjectID | undefined = createBy.data.createdByUserId;
|
||||
|
||||
if (createBy.props.userId) {
|
||||
userId = createBy.props.userId;
|
||||
}
|
||||
|
||||
if (createBy.data.createdByUser && createBy.data.createdByUser.id) {
|
||||
userId = createBy.data.createdByUser.id;
|
||||
}
|
||||
|
||||
const user: User | null = await UserService.findOneBy({
|
||||
query: {
|
||||
_id: userId?.toString()!,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user) {
|
||||
createBy.data.rootCause = `Monitor status created by ${user.name} (${user.email})`;
|
||||
}
|
||||
}
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
onCreate: OnCreate<MonitorStatusTimeline>,
|
||||
createdItem: MonitorStatusTimeline
|
||||
|
||||
@@ -5,9 +5,14 @@ import ProjectService from './ProjectService';
|
||||
import BillingService from './BillingService';
|
||||
import logger from '../Utils/Logger';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import BaseService from './BaseService';
|
||||
|
||||
export default class NotificationService {
|
||||
public static async rechargeBalance(
|
||||
export class NotificationService extends BaseService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public async rechargeBalance(
|
||||
projectId: ObjectID,
|
||||
amountInUSD: number
|
||||
): Promise<number> {
|
||||
@@ -84,7 +89,7 @@ export default class NotificationService {
|
||||
failedCallAndSMSBalanceChargeNotificationSentToOwners:
|
||||
false, // reset this flag
|
||||
lowCallAndSMSBalanceNotificationSentToOwners: false, // reset this flag
|
||||
notEnabledSmsNotificationSentToOwners: false,
|
||||
notEnabledSmsOrCallNotificationSentToOwners: false,
|
||||
},
|
||||
id: project.id!,
|
||||
props: {
|
||||
@@ -129,7 +134,7 @@ export default class NotificationService {
|
||||
}
|
||||
}
|
||||
|
||||
public static async rechargeIfBalanceIsLow(
|
||||
public async rechargeIfBalanceIsLow(
|
||||
projectId: ObjectID,
|
||||
options?: {
|
||||
autoRechargeSmsOrCallByBalanceInUSD: number;
|
||||
@@ -192,3 +197,5 @@ export default class NotificationService {
|
||||
return project?.smsOrCallCurrentBalanceInUSDCents || 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default new NotificationService();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/OnCallDuty';
|
||||
import Model from 'Model/Models/OnCallDutyPolicyCustomField';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
625
CommonServer/Services/OnCallDutyPolicyEscalationRuleService.ts
Normal file
625
CommonServer/Services/OnCallDutyPolicyEscalationRuleService.ts
Normal file
@@ -0,0 +1,625 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/OnCallDutyPolicyEscalationRule';
|
||||
import DatabaseService, {
|
||||
OnCreate,
|
||||
OnDelete,
|
||||
OnUpdate,
|
||||
} from './DatabaseService';
|
||||
import CreateBy from '../Types/Database/CreateBy';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import QueryHelper from '../Types/Database/QueryHelper';
|
||||
import DeleteBy from '../Types/Database/DeleteBy';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import LIMIT_MAX, { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
|
||||
import SortOrder from 'Common/Types/Database/SortOrder';
|
||||
import UpdateBy from '../Types/Database/UpdateBy';
|
||||
import Query from '../Types/Database/Query';
|
||||
import PositiveNumber from 'Common/Types/PositiveNumber';
|
||||
import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps';
|
||||
import OnCallDutyPolicyEscalationRuleUser from 'Model/Models/OnCallDutyPolicyEscalationRuleUser';
|
||||
import OnCallDutyPolicyEscalationRuleUserService from './OnCallDutyPolicyEscalationRuleUserService';
|
||||
import OnCallDutyPolicyEscalationRuleTeam from 'Model/Models/OnCallDutyPolicyEscalationRuleTeam';
|
||||
import OnCallDutyPolicyEscalationRuleTeamService from './OnCallDutyPolicyEscalationRuleTeamService';
|
||||
import TeamMemberService from './TeamMemberService';
|
||||
import UserNotificationEventType from 'Common/Types/UserNotification/UserNotificationEventType';
|
||||
import UserNotificationRuleService from './UserNotificationRuleService';
|
||||
import OnCallDutyPolicyExecutionLogTimeline from 'Model/Models/OnCallDutyPolicyExecutionLogTimeline';
|
||||
import OnCallDutyPolicyExecutionLogTimelineService from './OnCallDutyPolicyExecutionLogTimelineService';
|
||||
import OnCallDutyExecutionLogTimelineStatus from 'Common/Types/OnCallDutyPolicy/OnCalDutyExecutionLogTimelineStatus';
|
||||
import User from 'Model/Models/User';
|
||||
import OneUptimeDate from 'Common/Types/Date';
|
||||
import OnCallDutyPolicyExecutionLogService from './OnCallDutyPolicyExecutionLogService';
|
||||
import { IsBillingEnabled } from '../Config';
|
||||
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public async startRuleExecution(
|
||||
ruleId: ObjectID,
|
||||
options: {
|
||||
projectId: ObjectID;
|
||||
triggeredByIncidentId?: ObjectID | undefined;
|
||||
userNotificationEventType: UserNotificationEventType;
|
||||
onCallPolicyExecutionLogId: ObjectID;
|
||||
onCallPolicyId: ObjectID;
|
||||
}
|
||||
): Promise<void> {
|
||||
// add log timeline.
|
||||
|
||||
const rule: Model | null = await this.findOneById({
|
||||
id: ruleId,
|
||||
select: {
|
||||
_id: true,
|
||||
order: true,
|
||||
escalateAfterInMinutes: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!rule) {
|
||||
throw new BadDataException(
|
||||
`On Call Duty Policy Escalation Rule with id ${ruleId.toString()} not found`
|
||||
);
|
||||
}
|
||||
|
||||
await OnCallDutyPolicyExecutionLogService.updateOneById({
|
||||
id: options.onCallPolicyExecutionLogId,
|
||||
data: {
|
||||
lastEscalationRuleExecutedAt: OneUptimeDate.getCurrentDate(),
|
||||
lastExecutedEscalationRuleId: ruleId,
|
||||
lastExecutedEscalationRuleOrder: rule.order!,
|
||||
executeNextEscalationRuleInMinutes:
|
||||
rule.escalateAfterInMinutes || 0,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
const getNewLog: Function =
|
||||
(): OnCallDutyPolicyExecutionLogTimeline => {
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline =
|
||||
new OnCallDutyPolicyExecutionLogTimeline();
|
||||
|
||||
log.projectId = options.projectId;
|
||||
log.onCallDutyPolicyExecutionLogId =
|
||||
options.onCallPolicyExecutionLogId;
|
||||
log.onCallDutyPolicyId = options.onCallPolicyId;
|
||||
log.onCallDutyPolicyEscalationRuleId = ruleId;
|
||||
log.userNotificationEventType =
|
||||
options.userNotificationEventType;
|
||||
|
||||
if (options.triggeredByIncidentId) {
|
||||
log.triggeredByIncidentId = options.triggeredByIncidentId;
|
||||
}
|
||||
|
||||
return log;
|
||||
};
|
||||
|
||||
if (
|
||||
UserNotificationEventType.IncidentCreated ===
|
||||
options.userNotificationEventType &&
|
||||
!options.triggeredByIncidentId
|
||||
) {
|
||||
throw new BadDataException(
|
||||
'triggeredByIncidentId is required when userNotificationEventType is IncidentCreated'
|
||||
);
|
||||
}
|
||||
|
||||
const usersInRule: Array<OnCallDutyPolicyEscalationRuleUser> =
|
||||
await OnCallDutyPolicyEscalationRuleUserService.findBy({
|
||||
query: {
|
||||
onCallDutyPolicyEscalationRuleId: ruleId,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
select: {
|
||||
userId: true,
|
||||
},
|
||||
});
|
||||
|
||||
const teamsInRule: Array<OnCallDutyPolicyEscalationRuleTeam> =
|
||||
await OnCallDutyPolicyEscalationRuleTeamService.findBy({
|
||||
query: {
|
||||
onCallDutyPolicyEscalationRuleId: ruleId,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
select: {
|
||||
teamId: true,
|
||||
},
|
||||
});
|
||||
|
||||
// get unique users and notify all the users.
|
||||
|
||||
const startUserNotifcationRuleExecution: Function = async (
|
||||
userId: ObjectID,
|
||||
teamId: ObjectID | undefined
|
||||
): Promise<void> => {
|
||||
// no users in this rule. Skipping.
|
||||
let log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage = 'Sending notification to user.';
|
||||
log.status = OnCallDutyExecutionLogTimelineStatus.Executing;
|
||||
log.alertSentToUserId = userId;
|
||||
if (teamId) {
|
||||
log.userBelongsToTeamId = teamId;
|
||||
}
|
||||
|
||||
log = await OnCallDutyPolicyExecutionLogTimelineService.create({
|
||||
data: log,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
await UserNotificationRuleService.startUserNotificationRulesExecution(
|
||||
userId,
|
||||
{
|
||||
userNotificationEventType:
|
||||
options.userNotificationEventType!,
|
||||
triggeredByIncidentId:
|
||||
options.triggeredByIncidentId || undefined,
|
||||
onCallPolicyExecutionLogId:
|
||||
options.onCallPolicyExecutionLogId,
|
||||
onCallPolicyId: options.onCallPolicyId,
|
||||
onCallPolicyEscalationRuleId: ruleId,
|
||||
userBelongsToTeamId: teamId,
|
||||
onCallDutyPolicyExecutionLogTimelineId: log.id!,
|
||||
projectId: options.projectId,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const uniqueUserIds: Array<ObjectID> = [];
|
||||
|
||||
for (const teamInRule of teamsInRule) {
|
||||
const usersInTeam: Array<User> =
|
||||
await TeamMemberService.getUsersInTeam(teamInRule.teamId!);
|
||||
|
||||
for (const user of usersInTeam) {
|
||||
if (
|
||||
!uniqueUserIds.find((userId: ObjectID) => {
|
||||
return user.id?.toString() === userId.toString();
|
||||
})
|
||||
) {
|
||||
uniqueUserIds.push(user.id!);
|
||||
await startUserNotifcationRuleExecution(
|
||||
user.id!,
|
||||
teamInRule.teamId!
|
||||
);
|
||||
} else {
|
||||
// no users in this rule. Skipping.
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline =
|
||||
getNewLog();
|
||||
log.statusMessage =
|
||||
'Skipped because notification sent to this user already.';
|
||||
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
||||
log.alertSentToUserId = user.id!;
|
||||
log.userBelongsToTeamId = teamInRule.teamId!;
|
||||
|
||||
await OnCallDutyPolicyExecutionLogTimelineService.create({
|
||||
data: log,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const userRule of usersInRule) {
|
||||
if (
|
||||
!uniqueUserIds.find((userId: ObjectID) => {
|
||||
return userRule.userId?.toString() === userId.toString();
|
||||
})
|
||||
) {
|
||||
uniqueUserIds.push(userRule.userId!);
|
||||
await startUserNotifcationRuleExecution(
|
||||
userRule.userId!,
|
||||
undefined
|
||||
);
|
||||
} else {
|
||||
// no users in this rule. Skipping.
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage =
|
||||
'Skipped because notification sent to this user already.';
|
||||
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
||||
log.alertSentToUserId = userRule.userId!;
|
||||
|
||||
await OnCallDutyPolicyExecutionLogTimelineService.create({
|
||||
data: log,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueUserIds.length === 0) {
|
||||
// no users in this rule. Skipping.
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage = 'Skipped because no users in this rule.';
|
||||
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
||||
|
||||
await OnCallDutyPolicyExecutionLogTimelineService.create({
|
||||
data: log,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
onCreate: OnCreate<Model>,
|
||||
createdItem: Model
|
||||
): Promise<Model> {
|
||||
if (!createdItem.projectId) {
|
||||
throw new BadDataException('projectId is required');
|
||||
}
|
||||
|
||||
if (!createdItem.id) {
|
||||
throw new BadDataException('id is required');
|
||||
}
|
||||
|
||||
// add people in escalation rule.
|
||||
|
||||
if (
|
||||
onCreate.createBy.miscDataProps &&
|
||||
(onCreate.createBy.miscDataProps['teams'] ||
|
||||
onCreate.createBy.miscDataProps['users'])
|
||||
) {
|
||||
await this.addUsersAndTeams(
|
||||
createdItem.projectId,
|
||||
createdItem.id,
|
||||
createdItem.onCallDutyPolicyId!,
|
||||
(onCreate.createBy.miscDataProps['users'] as Array<ObjectID>) ||
|
||||
[],
|
||||
(onCreate.createBy.miscDataProps['teams'] as Array<ObjectID>) ||
|
||||
[],
|
||||
onCreate.createBy.props
|
||||
);
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
public async addUsersAndTeams(
|
||||
projectId: ObjectID,
|
||||
escalationRuleId: ObjectID,
|
||||
onCallDutyPolicyId: ObjectID,
|
||||
usersIds: Array<ObjectID>,
|
||||
teamIds: Array<ObjectID>,
|
||||
props: DatabaseCommonInteractionProps
|
||||
): Promise<void> {
|
||||
for (const userId of usersIds) {
|
||||
await this.addUser(
|
||||
projectId,
|
||||
escalationRuleId,
|
||||
onCallDutyPolicyId,
|
||||
userId,
|
||||
props
|
||||
);
|
||||
}
|
||||
|
||||
for (const teamId of teamIds) {
|
||||
await this.addTeam(
|
||||
projectId,
|
||||
escalationRuleId,
|
||||
onCallDutyPolicyId,
|
||||
teamId,
|
||||
props
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async addTeam(
|
||||
projectId: ObjectID,
|
||||
escalationRuleId: ObjectID,
|
||||
onCallDutyPolicyId: ObjectID,
|
||||
teamId: ObjectID,
|
||||
props: DatabaseCommonInteractionProps
|
||||
): Promise<void> {
|
||||
const teamInRule: OnCallDutyPolicyEscalationRuleTeam =
|
||||
new OnCallDutyPolicyEscalationRuleTeam();
|
||||
teamInRule.projectId = projectId;
|
||||
teamInRule.onCallDutyPolicyId = onCallDutyPolicyId;
|
||||
teamInRule.onCallDutyPolicyEscalationRuleId = escalationRuleId;
|
||||
teamInRule.teamId = teamId;
|
||||
|
||||
await OnCallDutyPolicyEscalationRuleTeamService.create({
|
||||
data: teamInRule,
|
||||
props,
|
||||
});
|
||||
}
|
||||
|
||||
public async addUser(
|
||||
projectId: ObjectID,
|
||||
escalationRuleId: ObjectID,
|
||||
onCallDutyPolicyId: ObjectID,
|
||||
userId: ObjectID,
|
||||
props: DatabaseCommonInteractionProps
|
||||
): Promise<void> {
|
||||
const userInRule: OnCallDutyPolicyEscalationRuleUser =
|
||||
new OnCallDutyPolicyEscalationRuleUser();
|
||||
userInRule.projectId = projectId;
|
||||
userInRule.onCallDutyPolicyId = onCallDutyPolicyId;
|
||||
userInRule.onCallDutyPolicyEscalationRuleId = escalationRuleId;
|
||||
userInRule.userId = userId;
|
||||
|
||||
await OnCallDutyPolicyEscalationRuleUserService.create({
|
||||
data: userInRule,
|
||||
props,
|
||||
});
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<Model>
|
||||
): Promise<OnCreate<Model>> {
|
||||
if (
|
||||
IsBillingEnabled &&
|
||||
createBy.props.currentPlan === PlanSelect.Free
|
||||
) {
|
||||
// then check no of policies and if it is more than one, return error
|
||||
const count: PositiveNumber = await this.countBy({
|
||||
query: {
|
||||
projectId: createBy.data.projectId!,
|
||||
onCallDutyPolicyId:
|
||||
createBy.data.onCallDutyPolicyId! ||
|
||||
createBy.data.onCallDutyPolicy?._id!,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (count.toNumber() >= 1) {
|
||||
throw new BadDataException(
|
||||
'You can only create one escalation rule in free plan.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!createBy.data.onCallDutyPolicyId) {
|
||||
throw new BadDataException(
|
||||
'Status Page Resource onCallDutyPolicyId is required'
|
||||
);
|
||||
}
|
||||
|
||||
if (!createBy.data.order) {
|
||||
const query: Query<Model> = {
|
||||
onCallDutyPolicyId: createBy.data.onCallDutyPolicyId,
|
||||
};
|
||||
|
||||
const count: PositiveNumber = await this.countBy({
|
||||
query: query,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
createBy.data.order = count.toNumber() + 1;
|
||||
}
|
||||
|
||||
await this.rearrangeOrder(
|
||||
createBy.data.order,
|
||||
createBy.data.onCallDutyPolicyId,
|
||||
true
|
||||
);
|
||||
|
||||
return {
|
||||
createBy: createBy,
|
||||
carryForward: null,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
deleteBy: DeleteBy<Model>
|
||||
): Promise<OnDelete<Model>> {
|
||||
if (!deleteBy.query._id && !deleteBy.props.isRoot) {
|
||||
throw new BadDataException(
|
||||
'_id should be present when deleting status page resource. Please try the delete with objectId'
|
||||
);
|
||||
}
|
||||
|
||||
let resource: Model | null = null;
|
||||
|
||||
if (!deleteBy.props.isRoot) {
|
||||
resource = await this.findOneBy({
|
||||
query: deleteBy.query,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
order: true,
|
||||
onCallDutyPolicyId: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
deleteBy,
|
||||
carryForward: resource,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onDeleteSuccess(
|
||||
onDelete: OnDelete<Model>,
|
||||
_itemIdsBeforeDelete: ObjectID[]
|
||||
): Promise<OnDelete<Model>> {
|
||||
const deleteBy: DeleteBy<Model> = onDelete.deleteBy;
|
||||
const resource: Model | null = onDelete.carryForward;
|
||||
|
||||
if (!deleteBy.props.isRoot && resource) {
|
||||
if (resource && resource.order && resource.onCallDutyPolicyId) {
|
||||
await this.rearrangeOrder(
|
||||
resource.order,
|
||||
resource.onCallDutyPolicyId,
|
||||
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
deleteBy: deleteBy,
|
||||
carryForward: null,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onBeforeUpdate(
|
||||
updateBy: UpdateBy<Model>
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (
|
||||
updateBy.data.order &&
|
||||
!updateBy.props.isRoot &&
|
||||
updateBy.query._id
|
||||
) {
|
||||
const resource: Model | null = await this.findOneBy({
|
||||
query: {
|
||||
_id: updateBy.query._id!,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
order: true,
|
||||
onCallDutyPolicyId: true,
|
||||
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
const currentOrder: number = resource?.order!;
|
||||
const newOrder: number = updateBy.data.order as number;
|
||||
|
||||
const resources: Array<Model> = await this.findBy({
|
||||
query: {
|
||||
onCallDutyPolicyId: resource?.onCallDutyPolicyId!,
|
||||
},
|
||||
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
order: true,
|
||||
onCallDutyPolicyId: true,
|
||||
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (currentOrder > newOrder) {
|
||||
// moving up.
|
||||
|
||||
for (const resource of resources) {
|
||||
if (
|
||||
resource.order! >= newOrder &&
|
||||
resource.order! < currentOrder
|
||||
) {
|
||||
// increment order.
|
||||
await this.updateOneBy({
|
||||
query: {
|
||||
_id: resource._id!,
|
||||
},
|
||||
data: {
|
||||
order: resource.order! + 1,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newOrder > currentOrder) {
|
||||
// moving down.
|
||||
|
||||
for (const resource of resources) {
|
||||
if (
|
||||
resource.order! < newOrder &&
|
||||
resource.order! >= currentOrder
|
||||
) {
|
||||
// increment order.
|
||||
await this.updateOneBy({
|
||||
query: {
|
||||
_id: resource._id!,
|
||||
},
|
||||
data: {
|
||||
order: resource.order! - 1,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { updateBy, carryForward: null };
|
||||
}
|
||||
|
||||
private async rearrangeOrder(
|
||||
currentOrder: number,
|
||||
onCallDutyPolicyId: ObjectID,
|
||||
increaseOrder: boolean = true
|
||||
): Promise<void> {
|
||||
// get status page resource with this order.
|
||||
const resources: Array<Model> = await this.findBy({
|
||||
query: {
|
||||
order: QueryHelper.greaterThanEqualTo(currentOrder),
|
||||
onCallDutyPolicyId: onCallDutyPolicyId,
|
||||
},
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
order: true,
|
||||
},
|
||||
sort: {
|
||||
order: SortOrder.Ascending,
|
||||
},
|
||||
});
|
||||
|
||||
let newOrder: number = currentOrder;
|
||||
|
||||
for (const resource of resources) {
|
||||
if (increaseOrder) {
|
||||
newOrder = resource.order! + 1;
|
||||
} else {
|
||||
newOrder = resource.order! - 1;
|
||||
}
|
||||
|
||||
await this.updateOneBy({
|
||||
query: {
|
||||
_id: resource._id!,
|
||||
},
|
||||
data: {
|
||||
order: newOrder,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
@@ -0,0 +1,10 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/OnCallDutyPolicyEscalationRuleTeam';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
@@ -0,0 +1,10 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/OnCallDutyPolicyEscalationRuleUser';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
98
CommonServer/Services/OnCallDutyPolicyExecutionLogService.ts
Normal file
98
CommonServer/Services/OnCallDutyPolicyExecutionLogService.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/OnCallDutyPolicyExecutionLog';
|
||||
import DatabaseService, { OnCreate } from './DatabaseService';
|
||||
import CreateBy from '../Types/Database/CreateBy';
|
||||
import OnCallDutyPolicyStatus from 'Common/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus';
|
||||
import OnCallDutyPolicyEscalationRule from 'Model/Models/OnCallDutyPolicyEscalationRule';
|
||||
import OnCallDutyPolicyEscalationRuleService from './OnCallDutyPolicyEscalationRuleService';
|
||||
import UserNotificationEventType from 'Common/Types/UserNotification/UserNotificationEventType';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<Model>
|
||||
): Promise<OnCreate<Model>> {
|
||||
if (!createBy.data.status) {
|
||||
createBy.data.status = OnCallDutyPolicyStatus.Scheduled;
|
||||
}
|
||||
|
||||
createBy.data.onCallPolicyExecutionRepeatCount = 1;
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
_onCreate: OnCreate<Model>,
|
||||
createdItem: Model
|
||||
): Promise<Model> {
|
||||
// get execution rules in this policy adn execute the first rule.
|
||||
const executionRule: OnCallDutyPolicyEscalationRule | null =
|
||||
await OnCallDutyPolicyEscalationRuleService.findOneBy({
|
||||
query: {
|
||||
projectId: createdItem.projectId!,
|
||||
onCallDutyPolicyId: createdItem.onCallDutyPolicyId!,
|
||||
order: 1,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (executionRule) {
|
||||
await this.updateOneById({
|
||||
id: createdItem.id!,
|
||||
data: {
|
||||
status: OnCallDutyPolicyStatus.Started,
|
||||
statusMessage: 'Execution started...',
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
await OnCallDutyPolicyEscalationRuleService.startRuleExecution(
|
||||
executionRule.id!,
|
||||
{
|
||||
projectId: createdItem.projectId!,
|
||||
triggeredByIncidentId: createdItem.triggeredByIncidentId,
|
||||
userNotificationEventType:
|
||||
UserNotificationEventType.IncidentCreated,
|
||||
onCallPolicyExecutionLogId: createdItem.id!,
|
||||
onCallPolicyId: createdItem.onCallDutyPolicyId!,
|
||||
}
|
||||
);
|
||||
|
||||
await this.updateOneById({
|
||||
id: createdItem.id!,
|
||||
data: {
|
||||
status: OnCallDutyPolicyStatus.Executing,
|
||||
statusMessage: 'First escalation rule executed....',
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await this.updateOneById({
|
||||
id: createdItem.id!,
|
||||
data: {
|
||||
status: OnCallDutyPolicyStatus.Error,
|
||||
statusMessage:
|
||||
'No Escalation Rules in Policy. Please add escalation rules to this policy.',
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
@@ -0,0 +1,10 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/OnCallDutyPolicyExecutionLogTimeline';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
74
CommonServer/Services/OnCallDutyPolicyService.ts
Normal file
74
CommonServer/Services/OnCallDutyPolicyService.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import DatabaseService from './DatabaseService';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import OnCallDutyPolicyExecutionLog from 'Model/Models/OnCallDutyPolicyExecutionLog';
|
||||
import OnCallDutyPolicy from 'Model/Models/OnCallDutyPolicy';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import OnCallDutyPolicyExecutionLogService from './OnCallDutyPolicyExecutionLogService';
|
||||
import UserNotificationEventType from 'Common/Types/UserNotification/UserNotificationEventType';
|
||||
import OnCallDutyPolicyStatus from 'Common/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus';
|
||||
|
||||
export class Service extends DatabaseService<OnCallDutyPolicy> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(OnCallDutyPolicy, postgresDatabase);
|
||||
}
|
||||
|
||||
public async executePolicy(
|
||||
policyId: ObjectID,
|
||||
options: {
|
||||
triggeredByIncidentId?: ObjectID | undefined;
|
||||
userNotificationEventType: UserNotificationEventType;
|
||||
}
|
||||
): Promise<void> {
|
||||
// execute this policy
|
||||
|
||||
if (
|
||||
UserNotificationEventType.IncidentCreated ===
|
||||
options.userNotificationEventType &&
|
||||
!options.triggeredByIncidentId
|
||||
) {
|
||||
throw new BadDataException(
|
||||
'triggeredByIncidentId is required when userNotificationEventType is IncidentCreated'
|
||||
);
|
||||
}
|
||||
|
||||
const policy: OnCallDutyPolicy | null = await this.findOneById({
|
||||
id: policyId,
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!policy) {
|
||||
throw new BadDataException(
|
||||
`On Call Duty Policy with id ${policyId.toString()} not found`
|
||||
);
|
||||
}
|
||||
|
||||
// add policy log.
|
||||
const log: OnCallDutyPolicyExecutionLog =
|
||||
new OnCallDutyPolicyExecutionLog();
|
||||
|
||||
log.projectId = policy.projectId!;
|
||||
log.onCallDutyPolicyId = policyId;
|
||||
log.userNotificationEventType = options.userNotificationEventType;
|
||||
log.statusMessage = 'Scheduled.';
|
||||
log.status = OnCallDutyPolicyStatus.Scheduled;
|
||||
|
||||
if (options.triggeredByIncidentId) {
|
||||
log.triggeredByIncidentId = options.triggeredByIncidentId;
|
||||
}
|
||||
|
||||
await OnCallDutyPolicyExecutionLogService.create({
|
||||
data: log,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user