mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 08:42:13 +02:00
Compare commits
503 Commits
dashboardi
...
7.0.3557
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea38e2621f | ||
|
|
b2cb95e1fc | ||
|
|
b174b9795a | ||
|
|
9d1caa8336 | ||
|
|
52e8669960 | ||
|
|
f0505725a7 | ||
|
|
7897641ef7 | ||
|
|
761f5f35e9 | ||
|
|
241586ff4a | ||
|
|
f8fc1a9dae | ||
|
|
6bbcc0a301 | ||
|
|
0e6604aa11 | ||
|
|
ade84a23ff | ||
|
|
6ff883b54e | ||
|
|
3546d92143 | ||
|
|
e932eb1b1d | ||
|
|
cbca712af8 | ||
|
|
8490128833 | ||
|
|
b80e126540 | ||
|
|
5494a2244e | ||
|
|
23be5b1736 | ||
|
|
9f3a9bc915 | ||
|
|
84d322f476 | ||
|
|
f94fbcc2ae | ||
|
|
0e85162b50 | ||
|
|
a5927f3681 | ||
|
|
0d37587199 | ||
|
|
4674578c90 | ||
|
|
87d280edbd | ||
|
|
d44ddd6781 | ||
|
|
7271481fb7 | ||
|
|
7f05ae7415 | ||
|
|
1e84b3a0cb | ||
|
|
20c7b11ecc | ||
|
|
6666f6e817 | ||
|
|
621e1ce207 | ||
|
|
1c42c58591 | ||
|
|
6a1b0d8718 | ||
|
|
bc244bfde1 | ||
|
|
984cb41efc | ||
|
|
076386f0d4 | ||
|
|
cb11a46cc9 | ||
|
|
6c7f1b5eb9 | ||
|
|
95709f1996 | ||
|
|
eaebcc748d | ||
|
|
13c2f6e73d | ||
|
|
f746d353a7 | ||
|
|
de1760bda7 | ||
|
|
a28b870c23 | ||
|
|
eb216e52cf | ||
|
|
c19913ac58 | ||
|
|
b55bb4ceeb | ||
|
|
26ec1aa5b2 | ||
|
|
7b733c32e9 | ||
|
|
3d34118f9e | ||
|
|
69a3a898f5 | ||
|
|
74d21e7c33 | ||
|
|
aecf1c38a6 | ||
|
|
8b3041301a | ||
|
|
af77d191e3 | ||
|
|
ad58125663 | ||
|
|
63650ba791 | ||
|
|
1c5a434ee3 | ||
|
|
102e64224f | ||
|
|
854fe3084a | ||
|
|
b6c6186625 | ||
|
|
92bdd5cf03 | ||
|
|
c2e78d122a | ||
|
|
bfc061ad47 | ||
|
|
98302a887a | ||
|
|
743db411d5 | ||
|
|
9537a9a13a | ||
|
|
0931705d6a | ||
|
|
6bfd9b657a | ||
|
|
493aef5b05 | ||
|
|
185f70e893 | ||
|
|
db2ecde486 | ||
|
|
ff3b7edec8 | ||
|
|
968b050d13 | ||
|
|
4328f7fc40 | ||
|
|
6ae3c28b8b | ||
|
|
8be022e34f | ||
|
|
ce6938396a | ||
|
|
537e2d02e7 | ||
|
|
80b9e48771 | ||
|
|
e0c3437c45 | ||
|
|
e5df15a53e | ||
|
|
a0f6e979b8 | ||
|
|
e20624a635 | ||
|
|
800583ddde | ||
|
|
f0bc71bee4 | ||
|
|
ba0dd4f2b0 | ||
|
|
63b560ad93 | ||
|
|
ae0553a1e5 | ||
|
|
fd4e2737e5 | ||
|
|
15f18c6d4f | ||
|
|
a84e32fe1b | ||
|
|
c09d97310f | ||
|
|
782eb45eb3 | ||
|
|
fb37da0aca | ||
|
|
ae2608e66f | ||
|
|
29565bc24c | ||
|
|
da7860fc3f | ||
|
|
0375e8c568 | ||
|
|
60c53b32e6 | ||
|
|
4d1797e9fa | ||
|
|
1ff4bde7b9 | ||
|
|
fae6d89a18 | ||
|
|
aa429abe01 | ||
|
|
203763aa95 | ||
|
|
0b69ae195f | ||
|
|
0756a43d62 | ||
|
|
13eb3205a2 | ||
|
|
9dcd295fd0 | ||
|
|
1fb84ea302 | ||
|
|
53ea3d32dc | ||
|
|
5c9ec28a4e | ||
|
|
04c2293378 | ||
|
|
6c672c541a | ||
|
|
169db73704 | ||
|
|
e980f00f1c | ||
|
|
66a594ed99 | ||
|
|
52c35c1e4d | ||
|
|
caa4103b48 | ||
|
|
f6069ca4a7 | ||
|
|
f519748c44 | ||
|
|
27de0f0ddb | ||
|
|
5426c22740 | ||
|
|
a55d4d1e02 | ||
|
|
2f65b1ee82 | ||
|
|
730dc56316 | ||
|
|
101e697a12 | ||
|
|
1c1488bca5 | ||
|
|
0e74adbd08 | ||
|
|
35947b4010 | ||
|
|
b304ceddbb | ||
|
|
cba6c48673 | ||
|
|
63b40cde75 | ||
|
|
439f2e87a2 | ||
|
|
fc0869d9fe | ||
|
|
fb5646e8c2 | ||
|
|
7538a47be5 | ||
|
|
8568cc0c89 | ||
|
|
2457de9757 | ||
|
|
a6859631ae | ||
|
|
e737444c52 | ||
|
|
b4a2726c81 | ||
|
|
5fc60491ff | ||
|
|
a7558535a6 | ||
|
|
408d06edb9 | ||
|
|
87be913388 | ||
|
|
1a034abe96 | ||
|
|
19bdfd66b9 | ||
|
|
982d051329 | ||
|
|
b66b1db2cb | ||
|
|
12e67a065d | ||
|
|
1f3cdc08ac | ||
|
|
5ebcba9f46 | ||
|
|
15e49c1b45 | ||
|
|
b71a657dea | ||
|
|
72e573bbc4 | ||
|
|
2113ffefd9 | ||
|
|
8da42884c2 | ||
|
|
e14c54c6cc | ||
|
|
10a199f3f5 | ||
|
|
2df97392b2 | ||
|
|
fcd2ecd118 | ||
|
|
e2e5533229 | ||
|
|
cf01fce011 | ||
|
|
100152ecc1 | ||
|
|
7b68c0b3c0 | ||
|
|
a7ad9b752b | ||
|
|
2e3ed42723 | ||
|
|
864e44d1a2 | ||
|
|
08cdb33e6e | ||
|
|
27647f529f | ||
|
|
4021650ea5 | ||
|
|
6a9f76c656 | ||
|
|
c3bba74107 | ||
|
|
16b9d4794e | ||
|
|
22e16d5c5b | ||
|
|
ef340e5fa0 | ||
|
|
20aff38458 | ||
|
|
16a1051280 | ||
|
|
fe9d3d3020 | ||
|
|
a0c0041cbd | ||
|
|
d755c62a51 | ||
|
|
5756623f45 | ||
|
|
8247f504c4 | ||
|
|
f05b0a15ee | ||
|
|
1abf1df1ee | ||
|
|
f1afab0b52 | ||
|
|
a0d33bf9c1 | ||
|
|
7c16fa7b42 | ||
|
|
5ba526d12e | ||
|
|
92174be7fd | ||
|
|
ece451b660 | ||
|
|
5ca740b43c | ||
|
|
70aae7c59a | ||
|
|
bb543ef010 | ||
|
|
64bba9246b | ||
|
|
511987bd70 | ||
|
|
19162504c8 | ||
|
|
96f5173fb9 | ||
|
|
8704f47b44 | ||
|
|
45803a8cd2 | ||
|
|
c04c2a3563 | ||
|
|
e61e7f3ba0 | ||
|
|
e438050f6e | ||
|
|
9601bdec93 | ||
|
|
c631dcfd44 | ||
|
|
4cabd2562a | ||
|
|
09e997c104 | ||
|
|
eee787be1c | ||
|
|
c9b0d4fbec | ||
|
|
946f82f978 | ||
|
|
8fc3fe4a98 | ||
|
|
3d321a038b | ||
|
|
ef06d47619 | ||
|
|
c8a966a2f7 | ||
|
|
32ffdf9174 | ||
|
|
d482cb00a9 | ||
|
|
6286b8bf4c | ||
|
|
b264f4a6b9 | ||
|
|
ec7d5fe5c2 | ||
|
|
4b9d770030 | ||
|
|
a8100e9b01 | ||
|
|
b43e892295 | ||
|
|
663f151051 | ||
|
|
282373b654 | ||
|
|
43faeb6e32 | ||
|
|
8180fcf386 | ||
|
|
e2cbd4d0ac | ||
|
|
084c259197 | ||
|
|
6ecd709f29 | ||
|
|
b935cef5a0 | ||
|
|
1d5e838afa | ||
|
|
90ca4b68cf | ||
|
|
031bd26b09 | ||
|
|
1296f37081 | ||
|
|
ba1a707156 | ||
|
|
d670cca559 | ||
|
|
f7e31a4f04 | ||
|
|
bb7917551f | ||
|
|
53238aee40 | ||
|
|
187d41e25f | ||
|
|
56f79a91c1 | ||
|
|
4dd6b5f32e | ||
|
|
f48a5a650c | ||
|
|
09a2a31d2b | ||
|
|
5fd60094ab | ||
|
|
0cfc9fbb56 | ||
|
|
2fc6200c47 | ||
|
|
437e5e7004 | ||
|
|
22e2c1f25c | ||
|
|
4799ed0434 | ||
|
|
0848dfc5d6 | ||
|
|
88cf2c3cb0 | ||
|
|
ca3855d109 | ||
|
|
36570f3944 | ||
|
|
df10a1900d | ||
|
|
eca3408598 | ||
|
|
9d1a2c40c7 | ||
|
|
cd58b72a9c | ||
|
|
ceead6eaba | ||
|
|
45a665b004 | ||
|
|
2dd1cd8453 | ||
|
|
8152a7f7ea | ||
|
|
55d962eed7 | ||
|
|
ebf5c83358 | ||
|
|
69e5fba5ff | ||
|
|
139ee62106 | ||
|
|
2d89431dc1 | ||
|
|
d506e658f0 | ||
|
|
180d02c53d | ||
|
|
e500886b12 | ||
|
|
7f7bcbc0a3 | ||
|
|
397231f1df | ||
|
|
f575afa151 | ||
|
|
b26cf4e876 | ||
|
|
450488eb4f | ||
|
|
14d3228786 | ||
|
|
811fd24cd5 | ||
|
|
098fb5be78 | ||
|
|
837d065b81 | ||
|
|
fe2b001c6d | ||
|
|
b08c047da7 | ||
|
|
79ff8b1f82 | ||
|
|
7da47d6e16 | ||
|
|
6e6f3c6c38 | ||
|
|
b3b3d9a0b7 | ||
|
|
16f0fe145a | ||
|
|
eea7209aaf | ||
|
|
c4c93f1cc5 | ||
|
|
0d19f56519 | ||
|
|
85d0ded200 | ||
|
|
c5134f0dd7 | ||
|
|
9e117f34d4 | ||
|
|
72f994d079 | ||
|
|
4a6edfa660 | ||
|
|
a20c05adb2 | ||
|
|
a286aba432 | ||
|
|
a3f1302e37 | ||
|
|
9393388cc5 | ||
|
|
d249fe16d9 | ||
|
|
7f6223f4c8 | ||
|
|
dc5e2c0d40 | ||
|
|
26f6a14e93 | ||
|
|
588de5ad27 | ||
|
|
8734938a82 | ||
|
|
06e7228041 | ||
|
|
38ad431b17 | ||
|
|
e0f5d8f1f2 | ||
|
|
e947d21060 | ||
|
|
41d347a1a7 | ||
|
|
5dc6ab6bb2 | ||
|
|
3492e54a9b | ||
|
|
adf92f3dc9 | ||
|
|
02b9f77e7c | ||
|
|
396f435755 | ||
|
|
5796db03f9 | ||
|
|
4029d72967 | ||
|
|
8d2cf500a0 | ||
|
|
5bfc954076 | ||
|
|
769f468273 | ||
|
|
8d75128603 | ||
|
|
ba4795e4b3 | ||
|
|
65f9f7c830 | ||
|
|
99e56f9312 | ||
|
|
b380e6d770 | ||
|
|
9d0add605d | ||
|
|
d4737841ce | ||
|
|
d6f9971cb6 | ||
|
|
8e4733b72f | ||
|
|
07c387289a | ||
|
|
956f786d1a | ||
|
|
56b2fbfb77 | ||
|
|
bba67afc36 | ||
|
|
d1dd0d7774 | ||
|
|
c7c6a54155 | ||
|
|
12fc9863d2 | ||
|
|
4ec718a966 | ||
|
|
91b2a6e44f | ||
|
|
aa2e79bd82 | ||
|
|
cc62b26002 | ||
|
|
6113b10c74 | ||
|
|
52a952f41e | ||
|
|
257b4283e1 | ||
|
|
31b4eba73f | ||
|
|
0dec6255f6 | ||
|
|
baabf84951 | ||
|
|
359c36e023 | ||
|
|
285fe7f524 | ||
|
|
093e8e5591 | ||
|
|
73ce957b57 | ||
|
|
5dbb80457a | ||
|
|
d53b2d0e1c | ||
|
|
c4256a0dea | ||
|
|
b8fc933acb | ||
|
|
45d447bf2c | ||
|
|
a0400be8cd | ||
|
|
3688381d4a | ||
|
|
1f5287c2e6 | ||
|
|
3e97d6bba1 | ||
|
|
32c0cbc4ad | ||
|
|
90f267105f | ||
|
|
eaa9a5f1a0 | ||
|
|
70da661041 | ||
|
|
b307a74319 | ||
|
|
5c2fa28fff | ||
|
|
2f8495e5b5 | ||
|
|
d3d9c46812 | ||
|
|
9e50d068db | ||
|
|
7232a3142c | ||
|
|
a1ca2e3f37 | ||
|
|
a5d993b999 | ||
|
|
854be1ddeb | ||
|
|
fe5b93f66e | ||
|
|
f259ddecd5 | ||
|
|
680be0e468 | ||
|
|
488a2b0b57 | ||
|
|
e0871e6b16 | ||
|
|
ab5acdef09 | ||
|
|
002c23b2a5 | ||
|
|
b10134fb30 | ||
|
|
93027ec0ae | ||
|
|
481b09531f | ||
|
|
4da1dd3f6b | ||
|
|
661d44d6b0 | ||
|
|
d6dacb6493 | ||
|
|
0ad5ee5997 | ||
|
|
5ad8f00388 | ||
|
|
450311de3c | ||
|
|
1bc4f07fa3 | ||
|
|
d091c93bfc | ||
|
|
2ff9b47f1c | ||
|
|
6b470e671f | ||
|
|
14c9174e24 | ||
|
|
e4beb13982 | ||
|
|
2b006e1765 | ||
|
|
f45c7f8d30 | ||
|
|
e3a2f95fc2 | ||
|
|
d27c161665 | ||
|
|
b9d6a69f00 | ||
|
|
fac334d58a | ||
|
|
a4913cc5bf | ||
|
|
0ad1a34e10 | ||
|
|
325fa0eb7a | ||
|
|
c02c1e6808 | ||
|
|
96a4a17320 | ||
|
|
23c169c6a3 | ||
|
|
6c4a4cad50 | ||
|
|
34c1af08db | ||
|
|
128aec9869 | ||
|
|
4fc2029a61 | ||
|
|
815ae7161d | ||
|
|
3a1f5c7120 | ||
|
|
eec51342de | ||
|
|
945cef653c | ||
|
|
93154aabc7 | ||
|
|
9244e49e6b | ||
|
|
74e43f0526 | ||
|
|
1fba734fd0 | ||
|
|
197e4e67e0 | ||
|
|
02afbb19be | ||
|
|
972e6cb98f | ||
|
|
b14f918d59 | ||
|
|
c05d4a0eea | ||
|
|
3732a5c95f | ||
|
|
1e0f6ff558 | ||
|
|
6a361e5b87 | ||
|
|
c94ac75a6f | ||
|
|
b49e40780a | ||
|
|
dd01fa0a3d | ||
|
|
a2218b01d0 | ||
|
|
8d9d83d679 | ||
|
|
546c74297f | ||
|
|
9fc1e73fd3 | ||
|
|
64e713f503 | ||
|
|
f254209410 | ||
|
|
2f738f8b58 | ||
|
|
e2da9b5bc3 | ||
|
|
04bfaf754a | ||
|
|
ab328b0987 | ||
|
|
521844a5ff | ||
|
|
c4096e7000 | ||
|
|
8afe8cf7fb | ||
|
|
fa8b52fa83 | ||
|
|
a8baa76096 | ||
|
|
8d5cef72b3 | ||
|
|
ef0f0ffa0b | ||
|
|
eef4e19dc9 | ||
|
|
5af41891dc | ||
|
|
4539b9d381 | ||
|
|
c1aadd7ce7 | ||
|
|
3b76b92fcb | ||
|
|
fe0dc51bef | ||
|
|
e279da47bf | ||
|
|
5d93000484 | ||
|
|
b826a78700 | ||
|
|
eded26d92c | ||
|
|
517d00dc9a | ||
|
|
96752f1473 | ||
|
|
bbc2e306f4 | ||
|
|
03e063c35b | ||
|
|
4c6c1381c8 | ||
|
|
4814451277 | ||
|
|
0c7b2ead8c | ||
|
|
6c6b80d3c8 | ||
|
|
76f9537002 | ||
|
|
c0994ff055 | ||
|
|
86694d9627 | ||
|
|
aa95f89b49 | ||
|
|
628b971dc9 | ||
|
|
ae002c0d88 | ||
|
|
a98fc6f784 | ||
|
|
5c459eede8 | ||
|
|
d9d2b615d2 | ||
|
|
86e6bca5e1 | ||
|
|
7cfff4787c | ||
|
|
491a8f05bc | ||
|
|
f67f1a64bd | ||
|
|
a31ef122a3 | ||
|
|
0a82d940fd | ||
|
|
6ec658b9a5 | ||
|
|
4e8de2303f | ||
|
|
19625d6cef | ||
|
|
e346b12011 | ||
|
|
2b11f2f2b8 | ||
|
|
3fb62cb358 | ||
|
|
108dfaccf8 | ||
|
|
eb20a3c9a2 | ||
|
|
988d828bb6 | ||
|
|
7fd0000c68 | ||
|
|
6286653dd4 | ||
|
|
9690a5897b | ||
|
|
eefac8703d | ||
|
|
077a3aad3b | ||
|
|
3ae72726b8 | ||
|
|
90c0e42eb1 | ||
|
|
8877ce6d12 | ||
|
|
1af5dae991 | ||
|
|
ee49f3e6dd |
85
.github/workflows/build.yml
vendored
85
.github/workflows/build.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -137,7 +137,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -169,7 +169,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -185,7 +185,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -200,7 +200,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -215,7 +215,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -231,7 +231,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -240,20 +240,65 @@ jobs:
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./Probe/Dockerfile .
|
||||
|
||||
docker-build-ingestor:
|
||||
docker-build-probe-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image probe api
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./Ingestor/Dockerfile .
|
||||
run: sudo docker build -f ./ProbeIngest/Dockerfile .
|
||||
|
||||
docker-build-open-telemetry-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image probe api
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./OpenTelemetryIngest/Dockerfile .
|
||||
|
||||
docker-build-incoming-request-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image probe api
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./IncomingRequestIngest/Dockerfile .
|
||||
|
||||
docker-build-fluent-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image probe api
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./FluentIngest/Dockerfile .
|
||||
|
||||
docker-build-status-page:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -261,7 +306,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
@@ -276,7 +321,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
4
.github/workflows/common-jobs.yaml
vendored
4
.github/workflows/common-jobs.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Helm
|
||||
run: |
|
||||
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install -y curl gcc
|
||||
- run: sudo apt-get install -y build-essential
|
||||
|
||||
150
.github/workflows/compile.yml
vendored
150
.github/workflows/compile.yml
vendored
@@ -15,10 +15,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Accounts && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -27,10 +27,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd IsolatedVM && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -39,10 +39,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install && npm run compile && npm run dep-check
|
||||
|
||||
compile-app:
|
||||
@@ -50,10 +50,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd App && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -62,10 +62,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Home && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -74,10 +74,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Worker && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -86,10 +86,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Workflow && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -98,10 +98,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd APIReference && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -110,10 +110,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Docs && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -122,10 +122,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Copilot && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -134,10 +134,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
|
||||
- run: cd Nginx && npm install && npm run compile && npm run dep-check
|
||||
@@ -158,10 +158,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
|
||||
- run: cd AdminDashboard && npm install && npm run compile && npm run dep-check
|
||||
@@ -171,10 +171,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
|
||||
- run: cd Dashboard && npm install && npm run compile && npm run dep-check
|
||||
@@ -185,10 +185,11 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: sudo apt-get update
|
||||
- run: cd Common && npm install
|
||||
- run: cd E2E && npm install && npm run compile && npm run dep-check
|
||||
|
||||
@@ -197,24 +198,61 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Probe && npm install && npm run compile && npm run dep-check
|
||||
|
||||
compile-ingestor:
|
||||
compile-probe-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Ingestor && npm install && npm run compile && npm run dep-check
|
||||
- run: cd ProbeIngest && npm install && npm run compile && npm run dep-check
|
||||
|
||||
compile-open-telemetry-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd OpenTelemetryIngest && npm install && npm run compile && npm run dep-check
|
||||
|
||||
|
||||
compile-incoming-request-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd IncomingRequestIngest && npm install && npm run compile && npm run dep-check
|
||||
|
||||
compile-fluent-ingest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd FluentIngest && npm install && npm run compile && npm run dep-check
|
||||
|
||||
|
||||
compile-status-page:
|
||||
@@ -222,10 +260,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
|
||||
- run: cd StatusPage && npm install && npm run compile && npm run dep-check
|
||||
@@ -235,9 +273,9 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd TestServer && npm install && npm run compile && npm run dep-check
|
||||
307
.github/workflows/release.yml
vendored
307
.github/workflows/release.yml
vendored
@@ -87,9 +87,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -147,9 +147,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -207,9 +207,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -267,9 +267,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -330,9 +330,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -390,9 +390,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -452,9 +452,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -512,9 +512,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -553,7 +553,7 @@ jobs:
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
ingestor-docker-image-deploy:
|
||||
probe-ingest-docker-image-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -562,8 +562,8 @@ jobs:
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/ingestor
|
||||
ghcr.io/oneuptime/ingestor
|
||||
oneuptime/probe-ingest
|
||||
ghcr.io/oneuptime/probe-ingest
|
||||
tags: |
|
||||
type=raw,value=release,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
|
||||
@@ -572,9 +572,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -585,7 +585,7 @@ jobs:
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy ingestor.
|
||||
# Build and deploy probe-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
@@ -603,7 +603,188 @@ jobs:
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./Ingestor/Dockerfile
|
||||
file: ./ProbeIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
open-telemetry-ingest-docker-image-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/open-telemetry-ingest
|
||||
ghcr.io/oneuptime/open-telemetry-ingest
|
||||
tags: |
|
||||
type=raw,value=release,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy open-telemetry-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./OpenTelemetryIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
|
||||
incoming-request-ingest-docker-image-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/incoming-request-ingest
|
||||
ghcr.io/oneuptime/incoming-request-ingest
|
||||
tags: |
|
||||
type=raw,value=release,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy incoming-request-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./IncomingRequestIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
fluent-ingest-docker-image-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/fluent-ingest
|
||||
ghcr.io/oneuptime/fluent-ingest
|
||||
tags: |
|
||||
type=raw,value=release,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy fluent-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./FluentIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
@@ -632,9 +813,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -693,9 +874,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -753,9 +934,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -814,9 +995,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -874,9 +1055,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -935,9 +1116,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -995,9 +1176,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1046,10 +1227,10 @@ jobs:
|
||||
PACKAGE_VERSION: 7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
- name: Publish Infrastructure Agent
|
||||
- name: Publish NPM Packages
|
||||
run: bash ./Scripts/NPM/PublishAllPackages.sh
|
||||
|
||||
|
||||
@@ -1090,9 +1271,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
# - name: Setup Git LFS
|
||||
# run: git lfs install
|
||||
@@ -1161,9 +1342,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1228,9 +1409,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1295,9 +1476,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1363,9 +1544,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1409,7 +1590,7 @@ jobs:
|
||||
|
||||
test-e2e-release-saas:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [copilot-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, ingestor-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
needs: [open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, fluent-ingest-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, probe-ingest-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy, incoming-request-ingest-docker-image-deploy]
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
@@ -1426,10 +1607,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: npm run prerun && bash ./Tests/Scripts/enable-billing-env-var.sh
|
||||
- name: Start Server with release tag
|
||||
run: npm run start
|
||||
@@ -1462,7 +1643,7 @@ jobs:
|
||||
test-e2e-release-self-hosted:
|
||||
runs-on: ubuntu-latest
|
||||
# After all the jobs runs
|
||||
needs: [copilot-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, ingestor-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
needs: [open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, incoming-request-ingest-docker-image-deploy, fluent-ingest-docker-image-deploy, docs-docker-image-deploy, api-reference-docker-image-deploy, workflow-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, probe-ingest-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, worker-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
@@ -1479,10 +1660,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: npm run prerun
|
||||
- name: Start Server with release tag
|
||||
run: npm run start
|
||||
@@ -1549,15 +1730,25 @@ jobs:
|
||||
uses: actions/setup-go@v4
|
||||
|
||||
- name: Install GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
uses: goreleaser/goreleaser-action@v6.1.0
|
||||
with:
|
||||
install-only: true
|
||||
|
||||
- name: GoReleaser Version
|
||||
run: goreleaser -v
|
||||
|
||||
# This tool is used to generate .rpm and .deb packages
|
||||
- name: Install NFPM
|
||||
run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
|
||||
|
||||
- name: Show GoReleaser version
|
||||
run: goreleaser -v
|
||||
|
||||
- name: Run GoReleaser
|
||||
run: cd InfrastructureAgent && export GORELEASER_CURRENT_TAG=7.0.${{needs.generate-build-number.outputs.build_number}} && goreleaser release --clean --snapshot
|
||||
|
||||
- name: Release MSI Images
|
||||
run: cd InfrastructureAgent && bash build-msi.sh 7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
# Upload binaries to github release
|
||||
- name: Release
|
||||
|
||||
349
.github/workflows/test-release.yaml
vendored
349
.github/workflows/test-release.yaml
vendored
@@ -56,9 +56,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
# - name: Setup Git LFS
|
||||
# run: git lfs install
|
||||
@@ -126,9 +126,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -188,9 +188,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -249,9 +249,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -310,9 +310,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -371,9 +371,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -432,9 +432,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -495,9 +495,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -558,9 +558,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -599,7 +599,7 @@ jobs:
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
ingestor-docker-image-deploy:
|
||||
probe-ingest-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -608,8 +608,8 @@ jobs:
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/ingestor
|
||||
ghcr.io/oneuptime/ingestor
|
||||
oneuptime/probe-ingest
|
||||
ghcr.io/oneuptime/probe-ingest
|
||||
tags: |
|
||||
type=raw,value=test,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
|
||||
@@ -619,9 +619,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -632,7 +632,7 @@ jobs:
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy ingestor.
|
||||
# Build and deploy probe-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
@@ -650,7 +650,190 @@ jobs:
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./Ingestor/Dockerfile
|
||||
file: ./ProbeIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
incoming-request-ingest-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/incoming-request-ingest
|
||||
ghcr.io/oneuptime/incoming-request-ingest
|
||||
tags: |
|
||||
type=raw,value=test,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
|
||||
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy incoming-request-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./IncomingRequestIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
open-telemetry-ingest-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/open-telemetry-ingest
|
||||
ghcr.io/oneuptime/open-telemetry-ingest
|
||||
tags: |
|
||||
type=raw,value=test,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
|
||||
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy incoming-request-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./OpenTelemetryIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
fluent-ingest-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/fluent-ingest
|
||||
ghcr.io/oneuptime/fluent-ingest
|
||||
tags: |
|
||||
type=raw,value=test,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
|
||||
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy probe-ingest.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./FluentIngest/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
@@ -680,9 +863,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -741,9 +924,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -802,9 +985,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -863,9 +1046,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -924,9 +1107,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -988,9 +1171,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1051,9 +1234,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1112,9 +1295,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1173,9 +1356,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1235,9 +1418,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1297,9 +1480,9 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
@@ -1343,14 +1526,14 @@ jobs:
|
||||
|
||||
test-helm-chart:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [llm-docker-image-deploy, copilot-docker-image-deploy, docs-docker-image-deploy, worker-docker-image-deploy, workflow-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, api-reference-docker-image-deploy, test-server-docker-image-deploy, test-docker-image-deploy, ingestor-docker-image-deploy, probe-docker-image-deploy, haraka-docker-image-deploy, dashboard-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, accounts-docker-image-deploy, otel-collector-docker-image-deploy, status-page-docker-image-deploy, nginx-docker-image-deploy, e2e-docker-image-deploy]
|
||||
needs: [llm-docker-image-deploy, open-telemetry-ingest-docker-image-deploy, copilot-docker-image-deploy, docs-docker-image-deploy, worker-docker-image-deploy, workflow-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, api-reference-docker-image-deploy, test-server-docker-image-deploy, test-docker-image-deploy, probe-ingest-docker-image-deploy, probe-docker-image-deploy, haraka-docker-image-deploy, dashboard-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, accounts-docker-image-deploy, otel-collector-docker-image-deploy, status-page-docker-image-deploy, nginx-docker-image-deploy, e2e-docker-image-deploy, fluent-ingest-docker-image-deploy, incoming-request-ingest-docker-image-deploy]
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd HelmChart && cd Tests && bash index.sh
|
||||
|
||||
test-e2e-test-saas:
|
||||
@@ -1372,10 +1555,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: npm run prerun && bash ./Tests/Scripts/change-release-to-test-tag.sh
|
||||
- name: Start Server with release tag
|
||||
run: npm run start
|
||||
@@ -1425,10 +1608,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: npm run prerun && bash ./Tests/Scripts/change-release-to-test-tag.sh
|
||||
- name: Start Server with release tag
|
||||
run: npm run start
|
||||
@@ -1457,6 +1640,56 @@ jobs:
|
||||
# Optional. Defaults to repository settings.
|
||||
retention-days: 7
|
||||
|
||||
infrastructure-agent-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
|
||||
- name: Install GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6.1.0
|
||||
with:
|
||||
install-only: true
|
||||
|
||||
- name: GoReleaser Version
|
||||
run: goreleaser -v
|
||||
|
||||
# This tool is used to generate .rpm and .deb packages
|
||||
- name: Install NFPM
|
||||
run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
|
||||
|
||||
- name: Show GoReleaser version
|
||||
run: goreleaser -v
|
||||
|
||||
- name: Run GoReleaser
|
||||
run: cd InfrastructureAgent && export GORELEASER_CURRENT_TAG=7.0.${{needs.generate-build-number.outputs.build_number}} && goreleaser release --clean --snapshot
|
||||
|
||||
- name: Release MSI Images
|
||||
run: cd InfrastructureAgent && bash build-msi.sh 7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
|
||||
- name: Upload Release Binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
# Run this on failure
|
||||
with:
|
||||
# Name of the artifact to upload.
|
||||
# Optional. Default is 'artifact'
|
||||
name: binaries
|
||||
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
# Required.
|
||||
path: |
|
||||
./InfrastructureAgent/dist
|
||||
|
||||
|
||||
# Duration after which artifact will expire in days. 0 means using default retention.
|
||||
# Minimum 1 day.
|
||||
# Maximum 90 days unless changed from the repository settings page.
|
||||
# Optional. Defaults to repository settings.
|
||||
retention-days: 7
|
||||
|
||||
|
||||
6
.github/workflows/test.common.yaml
vendored
6
.github/workflows/test.common.yaml
vendored
@@ -14,10 +14,10 @@ jobs:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
BILLING_PRIVATE_KEY: ${{secrets.TEST_BILLING_PRIVATE_KEY}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && bash test-setup.sh
|
||||
- run: cd Common && npm install && rm -rf build && npm run test
|
||||
|
||||
6
.github/workflows/test.e2e.yaml
vendored
6
.github/workflows/test.e2e.yaml
vendored
@@ -26,10 +26,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: npm run prerun && bash ./Tests/Scripts/enable-billing-env-var.sh
|
||||
- run: npm run dev
|
||||
- name: Wait for server to start
|
||||
|
||||
20
.github/workflows/test.fluent-ingest.yaml
vendored
Normal file
20
.github/workflows/test.fluent-ingest.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Fluent Ingest Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'hotfix-*' # excludes hotfix branches
|
||||
- 'release'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: cd FluentIngest && npm install && npm run test
|
||||
21
.github/workflows/test.incoming-request-ingest.yml
vendored
Normal file
21
.github/workflows/test.incoming-request-ingest.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Incoming Request Ingest Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'hotfix-*' # excludes hotfix branches
|
||||
- 'release'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: cd IncomingRequestIngest && npm install && npm run test
|
||||
|
||||
21
.github/workflows/test.open-telemetry-ingest.yaml
vendored
Normal file
21
.github/workflows/test.open-telemetry-ingest.yaml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: OpenTelemetryIngest Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'hotfix-*' # excludes hotfix branches
|
||||
- 'release'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
- run: cd OpenTelemetryIngest && npm install && npm run test
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Ingestor Test
|
||||
name: ProbeIngest Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -13,9 +13,9 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
- run: cd Ingestor && npm install && npm run test
|
||||
node-version: latest
|
||||
- run: cd ProbeIngest && npm install && npm run test
|
||||
|
||||
6
.github/workflows/test.probe.yaml
vendored
6
.github/workflows/test.probe.yaml
vendored
@@ -13,10 +13,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Common && npm install
|
||||
- run: cd Probe && npm install
|
||||
- run: cd Probe && npm run test
|
||||
|
||||
18
.github/workflows/test.yaml
vendored
18
.github/workflows/test.yaml
vendored
@@ -13,10 +13,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd App && npm install && npm run test
|
||||
|
||||
test-home:
|
||||
@@ -24,10 +24,10 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Home && npm install && npm run test
|
||||
|
||||
test-worker:
|
||||
@@ -35,8 +35,8 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: latest
|
||||
- run: cd Worker && npm install && npm run test
|
||||
@@ -1 +1 @@
|
||||
# Description: Copilot will run this script before we commit the changes to your repository.
|
||||
# Description: Copilot will run this script before we commit the changes to your repository.
|
||||
|
||||
66
.vscode/launch.json
vendored
66
.vscode/launch.json
vendored
@@ -93,7 +93,7 @@
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Worker",
|
||||
"localRoot": "${workspaceFolder}/Workflow",
|
||||
"name": "Workflow: Debug with Docker",
|
||||
"port": 8735,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
@@ -107,7 +107,7 @@
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Worker",
|
||||
"localRoot": "${workspaceFolder}/Docs",
|
||||
"name": "Docs: Debug with Docker",
|
||||
"port": 8738,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
@@ -121,7 +121,7 @@
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Worker",
|
||||
"localRoot": "${workspaceFolder}/APIReference",
|
||||
"name": "API Reference: Debug with Docker",
|
||||
"port": 8737,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
@@ -163,8 +163,8 @@
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Ingestor",
|
||||
"name": "Ingestor: Debug with Docker",
|
||||
"localRoot": "${workspaceFolder}/ProbeIngest",
|
||||
"name": "ProbeIngest: Debug with Docker",
|
||||
"port": 9932,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
@@ -175,6 +175,48 @@
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/IncomingRequestIngest",
|
||||
"name": "IncomingRequestIngest: Debug with Docker",
|
||||
"port": 9933,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/OpenTelemetryIngest",
|
||||
"name": "OpenTelemetryIngest: Debug with Docker",
|
||||
"port": 9938,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/FluentIngest",
|
||||
"name": "Fluent Ingest: Debug with Docker",
|
||||
"port": 9937,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/IsolatedVM",
|
||||
@@ -217,20 +259,6 @@
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Workers",
|
||||
"name": "Workers: Debug with Docker",
|
||||
"port": 9654,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/StatusPage",
|
||||
|
||||
@@ -17,10 +17,11 @@ const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
|
||||
const statusCheck: PromiseVoidFunction = async (): Promise<void> => {
|
||||
// Check the status of infrastructure components
|
||||
return await InfrastructureStatus.checkStatus({
|
||||
return await InfrastructureStatus.checkStatusWithRetry({
|
||||
checkClickhouseStatus: false,
|
||||
checkPostgresStatus: false,
|
||||
checkRedisStatus: false,
|
||||
retryCount: 3,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ const RegisterPage: () => JSX.Element = () => {
|
||||
]);
|
||||
|
||||
if (error) {
|
||||
return <ErrorMessage error={error} />;
|
||||
return <ErrorMessage message={error} />;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -41,7 +41,7 @@ const Logout: FunctionComponent = (): ReactElement => {
|
||||
]}
|
||||
>
|
||||
{!error ? <PageLoader isVisible={true} /> : <></>}
|
||||
{error ? <ErrorMessage error={error} /> : <></>}
|
||||
{error ? <ErrorMessage message={error} /> : <></>}
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <ErrorMessage error={error} />;
|
||||
return <ErrorMessage message={error} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -99,7 +99,7 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
title: "Description",
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: true,
|
||||
required: false,
|
||||
placeholder: "This probe is to monitor all the internal services.",
|
||||
},
|
||||
|
||||
@@ -170,6 +170,7 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
noValueMessage: "-",
|
||||
title: "Description",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import GlobalConfigAPI from "Common/Server/API/GlobalConfigAPI";
|
||||
import MonitorGroupAPI from "Common/Server/API/MonitorGroupAPI";
|
||||
import NotificationAPI from "Common/Server/API/NotificationAPI";
|
||||
import TelemetryAPI from "Common/Server/API/TelemetryAPI";
|
||||
import Ingestor from "Common/Server/API/ProbeAPI";
|
||||
import ProbeAPI from "Common/Server/API/ProbeAPI";
|
||||
import ProjectAPI from "Common/Server/API/ProjectAPI";
|
||||
import ProjectSsoAPI from "Common/Server/API/ProjectSSO";
|
||||
|
||||
@@ -156,9 +156,6 @@ import MonitorGroupOwnerUserService, {
|
||||
import MonitorGroupResourceService, {
|
||||
Service as MonitorGroupResourceServiceType,
|
||||
} from "Common/Server/Services/MonitorGroupResourceService";
|
||||
import MonitorMetricsByMinuteService, {
|
||||
MonitorMetricsByMinuteService as MonitorMetricsByMinuteServiceType,
|
||||
} from "Common/Server/Services/MonitorMetricsByMinuteService";
|
||||
import MonitorOwnerTeamService, {
|
||||
Service as MonitorOwnerTeamServiceType,
|
||||
} from "Common/Server/Services/MonitorOwnerTeamService";
|
||||
@@ -376,7 +373,6 @@ import FeatureSet from "Common/Server/Types/FeatureSet";
|
||||
import Express, { ExpressApplication } from "Common/Server/Utils/Express";
|
||||
import Log from "Common/Models/AnalyticsModels/Log";
|
||||
import Metric from "Common/Models/AnalyticsModels/Metric";
|
||||
import MonitorMetricsByMinute from "Common/Models/AnalyticsModels/MonitorMetricsByMinute";
|
||||
import Span from "Common/Models/AnalyticsModels/Span";
|
||||
import ApiKey from "Common/Models/DatabaseModels/ApiKey";
|
||||
import ApiKeyPermission from "Common/Models/DatabaseModels/ApiKeyPermission";
|
||||
@@ -500,6 +496,22 @@ import ScheduledMaintenanceTemplateOwnerUserService, {
|
||||
} from "Common/Server/Services/ScheduledMaintenanceTemplateOwnerUserService";
|
||||
import TableView from "Common/Models/DatabaseModels/TableView";
|
||||
|
||||
import IncidentFeed from "Common/Models/DatabaseModels/IncidentFeed";
|
||||
import AlertFeed from "Common/Models/DatabaseModels/AlertFeed";
|
||||
import ScheduledMaintenanceFeed from "Common/Models/DatabaseModels/ScheduledMaintenanceFeed";
|
||||
|
||||
import IncidentFeedService, {
|
||||
Service as IncidentFeedServiceType,
|
||||
} from "Common/Server/Services/IncidentFeedService";
|
||||
|
||||
import AlertFeedService, {
|
||||
Service as AlertFeedServiceType,
|
||||
} from "Common/Server/Services/AlertFeedService";
|
||||
|
||||
import ScheduledMaintenanceFeedService, {
|
||||
Service as ScheduledMaintenanceFeedServiceType,
|
||||
} from "Common/Server/Services/ScheduledMaintenanceFeedService";
|
||||
|
||||
const BaseAPIFeatureSet: FeatureSet = {
|
||||
init: async (): Promise<void> => {
|
||||
const app: ExpressApplication = Express.getExpressApp();
|
||||
@@ -530,6 +542,30 @@ const BaseAPIFeatureSet: FeatureSet = {
|
||||
).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<IncidentFeed, IncidentFeedServiceType>(
|
||||
IncidentFeed,
|
||||
IncidentFeedService,
|
||||
).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<AlertFeed, AlertFeedServiceType>(
|
||||
AlertFeed,
|
||||
AlertFeedService,
|
||||
).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<
|
||||
ScheduledMaintenanceFeed,
|
||||
ScheduledMaintenanceFeedServiceType
|
||||
>(ScheduledMaintenanceFeed, ScheduledMaintenanceFeedService).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<AlertNoteTemplate, AlertNoteTemplateServiceType>(
|
||||
@@ -673,14 +709,6 @@ const BaseAPIFeatureSet: FeatureSet = {
|
||||
).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAnalyticsAPI<
|
||||
MonitorMetricsByMinute,
|
||||
MonitorMetricsByMinuteServiceType
|
||||
>(MonitorMetricsByMinute, MonitorMetricsByMinuteService).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<TelemetryIngestionKey, TelemetryIngestionKeyServiceType>(
|
||||
@@ -1371,7 +1399,7 @@ const BaseAPIFeatureSet: FeatureSet = {
|
||||
);
|
||||
app.use(`/${APP_NAME.toLocaleLowerCase()}`, new UserEmailAPI().getRouter());
|
||||
app.use(`/${APP_NAME.toLocaleLowerCase()}`, new UserSMSAPI().getRouter());
|
||||
app.use(`/${APP_NAME.toLocaleLowerCase()}`, new Ingestor().getRouter());
|
||||
app.use(`/${APP_NAME.toLocaleLowerCase()}`, new ProbeAPI().getRouter());
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
|
||||
@@ -45,106 +45,112 @@ const router: ExpressRouter = Express.getRouter();
|
||||
router.get(
|
||||
"/service-provider-login",
|
||||
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
|
||||
if (!req.query["email"]) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("Email is required"),
|
||||
);
|
||||
}
|
||||
try {
|
||||
if (!req.query["email"]) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("Email is required"),
|
||||
);
|
||||
}
|
||||
|
||||
const email: Email = new Email(req.query["email"] as string);
|
||||
const email: Email = new Email(req.query["email"] as string);
|
||||
|
||||
if (!email) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("Email is required"),
|
||||
);
|
||||
}
|
||||
if (!email) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("Email is required"),
|
||||
);
|
||||
}
|
||||
|
||||
// get sso config for this user.
|
||||
// get sso config for this user.
|
||||
|
||||
const user: User | null = await UserService.findOneBy({
|
||||
query: { email: email },
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("No SSO config found for this user"),
|
||||
);
|
||||
}
|
||||
|
||||
const userId: ObjectID = user.id!;
|
||||
|
||||
if (!userId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("No SSO config found for this user"),
|
||||
);
|
||||
}
|
||||
|
||||
const projectUserBelongsTo: Array<ObjectID> = (
|
||||
await TeamMemberService.findBy({
|
||||
query: { userId: userId },
|
||||
const user: User | null = await UserService.findOneBy({
|
||||
query: { email: email },
|
||||
select: {
|
||||
projectId: true,
|
||||
_id: true,
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
})
|
||||
).map((teamMember: TeamMember) => {
|
||||
return teamMember.projectId!;
|
||||
});
|
||||
});
|
||||
|
||||
if (projectUserBelongsTo.length === 0) {
|
||||
return Response.sendErrorResponse(
|
||||
if (!user) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("No SSO config found for this user"),
|
||||
);
|
||||
}
|
||||
|
||||
const userId: ObjectID = user.id!;
|
||||
|
||||
if (!userId) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("No SSO config found for this user"),
|
||||
);
|
||||
}
|
||||
|
||||
const projectUserBelongsTo: Array<ObjectID> = (
|
||||
await TeamMemberService.findBy({
|
||||
query: { userId: userId },
|
||||
select: {
|
||||
projectId: true,
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
})
|
||||
).map((teamMember: TeamMember) => {
|
||||
return teamMember.projectId!;
|
||||
});
|
||||
|
||||
if (projectUserBelongsTo.length === 0) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("No SSO config found for this user"),
|
||||
);
|
||||
}
|
||||
|
||||
const projectSSOList: Array<ProjectSSO> = await ProjectSSOService.findBy({
|
||||
query: {
|
||||
projectId: QueryHelper.any(projectUserBelongsTo),
|
||||
isEnabled: true,
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
select: {
|
||||
name: true,
|
||||
description: true,
|
||||
_id: true,
|
||||
projectId: true,
|
||||
project: {
|
||||
name: true,
|
||||
} as Select<Project>,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendEntityArrayResponse(
|
||||
req,
|
||||
res,
|
||||
new BadRequestException("No SSO config found for this user"),
|
||||
projectSSOList,
|
||||
projectSSOList.length,
|
||||
ProjectSSO,
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
|
||||
Response.sendErrorResponse(req, res, err as Exception);
|
||||
}
|
||||
|
||||
const projectSSOList: Array<ProjectSSO> = await ProjectSSOService.findBy({
|
||||
query: {
|
||||
projectId: QueryHelper.any(projectUserBelongsTo),
|
||||
isEnabled: true,
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
select: {
|
||||
name: true,
|
||||
description: true,
|
||||
_id: true,
|
||||
projectId: true,
|
||||
project: {
|
||||
name: true,
|
||||
} as Select<Project>,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendEntityArrayResponse(
|
||||
req,
|
||||
res,
|
||||
projectSSOList,
|
||||
projectSSOList.length,
|
||||
ProjectSSO,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -153,7 +159,7 @@ router.get(
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
_next: NextFunction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
if (!req.params["projectId"]) {
|
||||
@@ -227,7 +233,9 @@ router.get(
|
||||
|
||||
return Response.redirect(req, res, samlRequestUrl);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
logger.error(err);
|
||||
|
||||
Response.sendErrorResponse(req, res, err as Exception);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -522,7 +530,8 @@ const loginUserWithSso: LoginUserWithSsoFunction = async (
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
Response.sendErrorResponse(req, res, new ServerException());
|
||||
|
||||
Response.sendErrorResponse(req, res, err as Exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{{> Start this}}
|
||||
|
||||
{{> CustomLogo this}}
|
||||
{{> EmailTitle title=(concat statusPageName " - Please confirm your subscription" ) }}
|
||||
|
||||
{{> InfoBlock info="You will be the first to hear from us when there are any incidents, announcements or scheduled maintenance events."}}
|
||||
|
||||
{{> ButtonBlock buttonUrl=confirmationUrl buttonText="Confirm Subscription"}}
|
||||
|
||||
{{> InfoBlock info="You can also view the status page by visiting this link:"}}
|
||||
{{> InfoBlock info=statusPageUrl}}
|
||||
|
||||
{{> UnsubscribeBlock this}}
|
||||
|
||||
{{> VerticalSpace this}}
|
||||
|
||||
{{> End this}}
|
||||
@@ -3,16 +3,15 @@
|
||||
{{> CustomLogo this}}
|
||||
{{> EmailTitle title=(concat "You have been subscribed to status page - " statusPageName) }}
|
||||
|
||||
{{> InfoBlock info=(concat "You have been subscribed to status page - " statusPageName)}}
|
||||
{{> InfoBlock info="You will be the first to hear from us when there are any incidents, announcements or scheduled maintenance events."}}
|
||||
|
||||
{{> ButtonBlock buttonUrl=statusPageUrl buttonText="Go to Status Page"}}
|
||||
|
||||
{{> InfoBlock info="You can also view the status page by visiting these link:"}}
|
||||
{{> InfoBlock info="You can also view the status page by visiting this link:"}}
|
||||
{{> InfoBlock info=statusPageUrl}}
|
||||
|
||||
{{> UnsubscribeBlock this}}
|
||||
|
||||
{{> VerticalSpace this}}
|
||||
|
||||
{{> End this}}
|
||||
{{> End this}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{> Start this}}
|
||||
|
||||
{{> CustomLogo this}}
|
||||
{{> EmailTitle title=(concat "Incident: " incidentTitle) }}
|
||||
{{> EmailTitle title=emailTitle }}
|
||||
|
||||
{{> InfoBlock info="Incident state has changed. Here are the details: "}}
|
||||
|
||||
|
||||
37
App/Index.ts
37
App/Index.ts
@@ -24,10 +24,42 @@ const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
|
||||
const statusCheck: PromiseVoidFunction = async (): Promise<void> => {
|
||||
// Check the status of infrastructure components
|
||||
return await InfrastructureStatus.checkStatus({
|
||||
return await InfrastructureStatus.checkStatusWithRetry({
|
||||
checkClickhouseStatus: true,
|
||||
checkPostgresStatus: true,
|
||||
checkRedisStatus: true,
|
||||
retryCount: 3,
|
||||
});
|
||||
};
|
||||
|
||||
const globalCacheCheck: PromiseVoidFunction = async (): Promise<void> => {
|
||||
// Check the status of cache
|
||||
return await InfrastructureStatus.checkStatusWithRetry({
|
||||
checkClickhouseStatus: false,
|
||||
checkPostgresStatus: false,
|
||||
checkRedisStatus: true,
|
||||
retryCount: 3,
|
||||
});
|
||||
};
|
||||
|
||||
const analyticsDatabaseCheck: PromiseVoidFunction =
|
||||
async (): Promise<void> => {
|
||||
// Check the status of analytics database
|
||||
return await InfrastructureStatus.checkStatusWithRetry({
|
||||
checkClickhouseStatus: true,
|
||||
checkPostgresStatus: false,
|
||||
checkRedisStatus: false,
|
||||
retryCount: 3,
|
||||
});
|
||||
};
|
||||
|
||||
const databaseCheck: PromiseVoidFunction = async (): Promise<void> => {
|
||||
// Check the status of database
|
||||
return await InfrastructureStatus.checkStatusWithRetry({
|
||||
checkClickhouseStatus: false,
|
||||
checkPostgresStatus: true,
|
||||
checkRedisStatus: false,
|
||||
retryCount: 3,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -37,6 +69,9 @@ const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
statusOptions: {
|
||||
liveCheck: statusCheck,
|
||||
readyCheck: statusCheck,
|
||||
globalCacheCheck: globalCacheCheck,
|
||||
analyticsDatabaseCheck: analyticsDatabaseCheck,
|
||||
databaseCheck: databaseCheck,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import AnalyticsBaseModel from "./AnalyticsBaseModel/AnalyticsBaseModel";
|
||||
import Log from "./Log";
|
||||
import Metric from "./Metric";
|
||||
import MonitorMetricsByMinute from "./MonitorMetricsByMinute";
|
||||
import Span from "./Span";
|
||||
import TelemetryAttribute from "./TelemetryAttribute";
|
||||
import ExceptionInstance from "./ExceptionInstance";
|
||||
@@ -10,7 +9,6 @@ const AnalyticsModels: Array<{ new (): AnalyticsBaseModel }> = [
|
||||
Log,
|
||||
Span,
|
||||
Metric,
|
||||
MonitorMetricsByMinute,
|
||||
TelemetryAttribute,
|
||||
ExceptionInstance,
|
||||
];
|
||||
|
||||
@@ -19,6 +19,13 @@ export enum MetricPointType {
|
||||
ExponentialHistogram = "ExponentialHistogram",
|
||||
}
|
||||
|
||||
export enum ServiceType {
|
||||
OpenTelemetry = "OpenTelemetry",
|
||||
Monitor = "Monitor",
|
||||
Alert = "Alert",
|
||||
Incident = "Incident",
|
||||
}
|
||||
|
||||
export default class Metric extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
super({
|
||||
@@ -78,10 +85,11 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
},
|
||||
}),
|
||||
|
||||
// this can also be the monitor id or the telemetry service id.
|
||||
new AnalyticsTableColumn({
|
||||
key: "serviceId",
|
||||
title: "Service ID",
|
||||
description: "ID of the Service which created the log",
|
||||
description: "ID of the Service which created the Metric",
|
||||
required: true,
|
||||
type: TableColumnType.ObjectID,
|
||||
accessControl: {
|
||||
@@ -101,6 +109,30 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
},
|
||||
}),
|
||||
|
||||
// this can also be the monitor id or the telemetry service id.
|
||||
new AnalyticsTableColumn({
|
||||
key: "serviceType",
|
||||
title: "Service Type",
|
||||
description: "Type of the service that this telemetry belongs to",
|
||||
required: false,
|
||||
type: TableColumnType.Text,
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadTelemetryServiceLog,
|
||||
],
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateTelemetryServiceLog,
|
||||
],
|
||||
update: [],
|
||||
},
|
||||
}),
|
||||
|
||||
// add name and description
|
||||
|
||||
new AnalyticsTableColumn({
|
||||
@@ -539,6 +571,10 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
return this.getColumnValue("serviceId") as ObjectID | undefined;
|
||||
}
|
||||
|
||||
public get serviceType(): ServiceType | undefined {
|
||||
return this.getColumnValue("serviceType") as ServiceType | undefined;
|
||||
}
|
||||
|
||||
public get name(): string | undefined {
|
||||
return this.getColumnValue("name") as string | undefined;
|
||||
}
|
||||
@@ -595,6 +631,10 @@ export default class Metric extends AnalyticsBaseModel {
|
||||
this.setColumnValue("serviceId", v);
|
||||
}
|
||||
|
||||
public set serviceType(v: ServiceType | undefined) {
|
||||
this.setColumnValue("serviceType", v);
|
||||
}
|
||||
|
||||
public get time(): Date | undefined {
|
||||
return this.getColumnValue("time") as Date | undefined;
|
||||
}
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
import AnalyticsBaseModel from "./AnalyticsBaseModel/AnalyticsBaseModel";
|
||||
import Route from "../../Types/API/Route";
|
||||
import AnalyticsTableEngine from "../../Types/AnalyticsDatabase/AnalyticsTableEngine";
|
||||
import AnalyticsTableColumn from "../../Types/AnalyticsDatabase/TableColumn";
|
||||
import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
|
||||
import BrowserType from "../../Types/BrowserType";
|
||||
import { JSONObject } from "../../Types/JSON";
|
||||
import { CheckOn } from "../../Types/Monitor/CriteriaFilter";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Permission from "../../Types/Permission";
|
||||
import ScreenSizeType from "../../Types/ScreenSizeType";
|
||||
|
||||
export interface MonitorMetricsMiscData {
|
||||
diskPath?: string;
|
||||
probeId?: string;
|
||||
browserType?: BrowserType;
|
||||
screenSizeType?: ScreenSizeType;
|
||||
}
|
||||
|
||||
export default class MonitorMetricsByMinute extends AnalyticsBaseModel {
|
||||
public constructor() {
|
||||
super({
|
||||
tableName: "MonitorMetrics",
|
||||
tableEngine: AnalyticsTableEngine.MergeTree,
|
||||
singularName: "Monitor Metric",
|
||||
pluralName: "Monitor Metrics",
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectMonitor,
|
||||
],
|
||||
create: [],
|
||||
update: [],
|
||||
delete: [],
|
||||
},
|
||||
crudApiPath: new Route("/monitor-metrics"),
|
||||
tableColumns: [
|
||||
new AnalyticsTableColumn({
|
||||
key: "projectId",
|
||||
title: "Project ID",
|
||||
description: "ID of project",
|
||||
required: true,
|
||||
type: TableColumnType.ObjectID,
|
||||
isTenantId: true,
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectMonitor,
|
||||
],
|
||||
create: [],
|
||||
update: [],
|
||||
},
|
||||
}),
|
||||
|
||||
new AnalyticsTableColumn({
|
||||
key: "monitorId",
|
||||
title: "Monitor ID",
|
||||
description: "ID of the Monitor which this metric belongs to",
|
||||
required: true,
|
||||
type: TableColumnType.ObjectID,
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectMonitor,
|
||||
],
|
||||
create: [],
|
||||
update: [],
|
||||
},
|
||||
}),
|
||||
|
||||
new AnalyticsTableColumn({
|
||||
key: "metricType",
|
||||
title: "Metric Type",
|
||||
description: "Type of metric",
|
||||
required: true,
|
||||
type: TableColumnType.Text,
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectMonitor,
|
||||
],
|
||||
create: [],
|
||||
update: [],
|
||||
},
|
||||
}),
|
||||
|
||||
new AnalyticsTableColumn({
|
||||
key: "metricValue",
|
||||
title: "Metric Value",
|
||||
description: "Value of the metric",
|
||||
required: true,
|
||||
type: TableColumnType.Number,
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectMonitor,
|
||||
],
|
||||
create: [],
|
||||
update: [],
|
||||
},
|
||||
}),
|
||||
|
||||
new AnalyticsTableColumn({
|
||||
key: "miscData",
|
||||
title: "Misc Data",
|
||||
description: "Misc data for the metric (if any)",
|
||||
required: false,
|
||||
type: TableColumnType.JSON,
|
||||
accessControl: {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectMonitor,
|
||||
],
|
||||
create: [],
|
||||
update: [],
|
||||
},
|
||||
}),
|
||||
],
|
||||
sortKeys: ["projectId", "monitorId", "createdAt"],
|
||||
primaryKeys: ["projectId", "monitorId"],
|
||||
});
|
||||
}
|
||||
|
||||
public get projectId(): ObjectID | undefined {
|
||||
return this.getColumnValue("projectId") as ObjectID | undefined;
|
||||
}
|
||||
|
||||
public set projectId(v: ObjectID | undefined) {
|
||||
this.setColumnValue("projectId", v);
|
||||
}
|
||||
|
||||
public get monitorId(): ObjectID | undefined {
|
||||
return this.getColumnValue("monitorId") as ObjectID | undefined;
|
||||
}
|
||||
|
||||
public set monitorId(v: ObjectID | undefined) {
|
||||
this.setColumnValue("monitorId", v);
|
||||
}
|
||||
|
||||
public get metricType(): CheckOn | undefined {
|
||||
return this.getColumnValue("metricType") as CheckOn | undefined;
|
||||
}
|
||||
|
||||
public set metricType(v: CheckOn | undefined) {
|
||||
this.setColumnValue("metricType", v);
|
||||
}
|
||||
|
||||
public get metricValue(): number | undefined {
|
||||
return this.getColumnValue("metricValue") as number | undefined;
|
||||
}
|
||||
|
||||
public set metricValue(v: number | undefined) {
|
||||
this.setColumnValue("metricValue", v);
|
||||
}
|
||||
|
||||
public get miscData(): MonitorMetricsMiscData | undefined {
|
||||
return this.getColumnValue("miscData") as
|
||||
| MonitorMetricsMiscData
|
||||
| undefined;
|
||||
}
|
||||
|
||||
public set miscData(v: MonitorMetricsMiscData | undefined) {
|
||||
this.setColumnValue("miscData", v as JSONObject);
|
||||
}
|
||||
}
|
||||
@@ -801,7 +801,6 @@ export default class Alert extends BaseModel {
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
|
||||
526
Common/Models/DatabaseModels/AlertFeed.ts
Normal file
526
Common/Models/DatabaseModels/AlertFeed.ts
Normal file
@@ -0,0 +1,526 @@
|
||||
import Alert from "./Alert";
|
||||
import Project from "./Project";
|
||||
import User from "./User";
|
||||
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
|
||||
import Route from "../../Types/API/Route";
|
||||
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
|
||||
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
|
||||
import CanAccessIfCanReadOn from "../../Types/Database/CanAccessIfCanReadOn";
|
||||
import ColumnType from "../../Types/Database/ColumnType";
|
||||
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
||||
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
||||
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
|
||||
import TableColumn from "../../Types/Database/TableColumn";
|
||||
import TableColumnType from "../../Types/Database/TableColumnType";
|
||||
import TableMetadata from "../../Types/Database/TableMetadata";
|
||||
import TenantColumn from "../../Types/Database/TenantColumn";
|
||||
import IconProp from "../../Types/Icon/IconProp";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Permission from "../../Types/Permission";
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
||||
import ColumnLength from "../../Types/Database/ColumnLength";
|
||||
import Color from "../../Types/Color";
|
||||
|
||||
export enum AlertFeedEventType {
|
||||
PublicNote = "PublicNote",
|
||||
SubscriberNotificationSent = "SubscriberNotificationSent",
|
||||
OwnerNotificationSent = "OwnerNotificationSent",
|
||||
OwnerUserAdded = "OwnerUserAdded",
|
||||
OwnerTeamAdded = "OwnerTeamAdded",
|
||||
AlertCreated = "AlertCreated",
|
||||
AlertStateChanged = "AlertStateChanged",
|
||||
PrivateNote = "PrivateNote",
|
||||
AlertUpdated = "AlertUpdated",
|
||||
RootCause = "RootCause",
|
||||
RemediationNotes = "RemediationNotes",
|
||||
OwnerUserRemoved = "OwnerUserRemoved",
|
||||
OwnerTeamRemoved = "OwnerTeamRemoved",
|
||||
OnCallPolicy = "OnCallPolicy",
|
||||
OnCallNotification = "OnCallNotification",
|
||||
}
|
||||
|
||||
@EnableDocumentation()
|
||||
@CanAccessIfCanReadOn("alert")
|
||||
@TenantColumn("projectId")
|
||||
@TableAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
delete: [],
|
||||
update: [],
|
||||
})
|
||||
@EnableWorkflow({
|
||||
create: true,
|
||||
delete: true,
|
||||
update: true,
|
||||
read: true,
|
||||
})
|
||||
@CrudApiEndpoint(new Route("/alert-feed"))
|
||||
@Entity({
|
||||
name: "AlertFeed",
|
||||
})
|
||||
@TableMetadata({
|
||||
tableName: "AlertFeed",
|
||||
singularName: "Alert Feed",
|
||||
pluralName: "Alert Feeds",
|
||||
icon: IconProp.List,
|
||||
tableDescription:
|
||||
"Log of the entire alert state change. This is a log of all the alert state changes, public notes, more etc.",
|
||||
})
|
||||
export default class AlertFeed extends BaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "projectId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Project,
|
||||
title: "Project",
|
||||
description: "Relation to Project Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Project;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "projectId" })
|
||||
public project?: Project = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Project ID",
|
||||
description: "ID of your OneUptime Project in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public projectId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "alertId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Alert,
|
||||
title: "Alert",
|
||||
description: "Relation to Alert in which this resource belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Alert;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "alertId" })
|
||||
public alert?: Alert = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
title: "Alert ID",
|
||||
description: "Relation to Alert ID in which this resource belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public alertId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "createdByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
title: "Created by User",
|
||||
description:
|
||||
"Relation to User who created this object (if this object was created by a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "createdByUserId" })
|
||||
public createdByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Created by User ID",
|
||||
description:
|
||||
"User ID who created this object (if this object was created by a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public createdByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "deletedByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
title: "Deleted by User",
|
||||
description:
|
||||
"Relation to User who deleted this object (if this object was deleted by a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
cascade: false,
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "deletedByUserId" })
|
||||
public deletedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Deleted by User ID",
|
||||
description:
|
||||
"User ID who deleted this object (if this object was deleted by a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public deletedByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: true,
|
||||
title: "Log (in Markdown)",
|
||||
description: "Log of the entire alert state change in Markdown",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Markdown,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
})
|
||||
public feedInfoInMarkdown?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
title: "More Information (in Markdown)",
|
||||
description: "More information in Markdown",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Markdown,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public moreInformationInMarkdown?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ShortText,
|
||||
required: true,
|
||||
title: "Alert Feed Event",
|
||||
description: "Alert Feed Event",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ShortText,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
})
|
||||
public alertFeedEventType?: AlertFeedEventType = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Color,
|
||||
required: true,
|
||||
title: "Color",
|
||||
description: "Display color for the alert log",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Color,
|
||||
length: ColumnLength.Color,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
transformer: Color.getDatabaseTransformer(),
|
||||
})
|
||||
public displayColor?: Color = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "userId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
title: "User",
|
||||
description:
|
||||
"Relation to User who this feed belongs to (if this feed belongs to a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "userId" })
|
||||
public user?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "User ID",
|
||||
description:
|
||||
"User who this feed belongs to (if this feed belongs to a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public userId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateAlertFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadAlertFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
title: "Feed Posted At",
|
||||
description: "Date and time when the feed was posted",
|
||||
type: TableColumnType.Date,
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Date,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public postedAt?: Date = undefined;
|
||||
}
|
||||
@@ -853,9 +853,13 @@ export default class Incident extends BaseModel {
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectIncident,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditProjectIncident,
|
||||
],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
@@ -1087,4 +1091,33 @@ export default class Incident extends BaseModel {
|
||||
nullable: true,
|
||||
})
|
||||
public telemetryQuery?: TelemetryQuery = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateProjectIncident,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectIncident,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: false,
|
||||
required: false,
|
||||
type: TableColumnType.Number,
|
||||
title: "Incident Number",
|
||||
description: "Incident Number",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Number,
|
||||
nullable: true,
|
||||
})
|
||||
public incidentNumber?: number = undefined;
|
||||
}
|
||||
|
||||
526
Common/Models/DatabaseModels/IncidentFeed.ts
Normal file
526
Common/Models/DatabaseModels/IncidentFeed.ts
Normal file
@@ -0,0 +1,526 @@
|
||||
import Incident from "./Incident";
|
||||
import Project from "./Project";
|
||||
import User from "./User";
|
||||
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
|
||||
import Route from "../../Types/API/Route";
|
||||
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
|
||||
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
|
||||
import CanAccessIfCanReadOn from "../../Types/Database/CanAccessIfCanReadOn";
|
||||
import ColumnType from "../../Types/Database/ColumnType";
|
||||
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
||||
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
||||
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
|
||||
import TableColumn from "../../Types/Database/TableColumn";
|
||||
import TableColumnType from "../../Types/Database/TableColumnType";
|
||||
import TableMetadata from "../../Types/Database/TableMetadata";
|
||||
import TenantColumn from "../../Types/Database/TenantColumn";
|
||||
import IconProp from "../../Types/Icon/IconProp";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Permission from "../../Types/Permission";
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
||||
import Color from "../../Types/Color";
|
||||
import ColumnLength from "../../Types/Database/ColumnLength";
|
||||
|
||||
export enum IncidentFeedEventType {
|
||||
PublicNote = "PublicNote",
|
||||
SubscriberNotificationSent = "SubscriberNotificationSent",
|
||||
OwnerNotificationSent = "OwnerNotificationSent",
|
||||
OwnerUserAdded = "OwnerUserAdded",
|
||||
OwnerTeamAdded = "OwnerTeamAdded",
|
||||
IncidentCreated = "IncidentCreated",
|
||||
IncidentStateChanged = "IncidentStateChanged",
|
||||
PrivateNote = "PrivateNote",
|
||||
IncidentUpdated = "IncidentUpdated",
|
||||
RootCause = "RootCause",
|
||||
RemediationNotes = "RemediationNotes",
|
||||
OwnerUserRemoved = "OwnerUserRemoved",
|
||||
OwnerTeamRemoved = "OwnerTeamRemoved",
|
||||
OnCallPolicy = "OnCallPolicy",
|
||||
OnCallNotification = "OnCallNotification",
|
||||
}
|
||||
|
||||
@EnableDocumentation()
|
||||
@CanAccessIfCanReadOn("incident")
|
||||
@TenantColumn("projectId")
|
||||
@TableAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
delete: [],
|
||||
update: [],
|
||||
})
|
||||
@EnableWorkflow({
|
||||
create: true,
|
||||
delete: true,
|
||||
update: true,
|
||||
read: true,
|
||||
})
|
||||
@CrudApiEndpoint(new Route("/incident-feed"))
|
||||
@Entity({
|
||||
name: "IncidentFeed",
|
||||
})
|
||||
@TableMetadata({
|
||||
tableName: "IncidentFeed",
|
||||
singularName: "Incident Feed",
|
||||
pluralName: "Incident Feeds",
|
||||
icon: IconProp.List,
|
||||
tableDescription:
|
||||
"Log of the entire incident state change. This is a log of all the incident state changes, public notes, more etc.",
|
||||
})
|
||||
export default class IncidentFeed extends BaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "projectId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Project,
|
||||
title: "Project",
|
||||
description: "Relation to Project Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Project;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "projectId" })
|
||||
public project?: Project = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Project ID",
|
||||
description: "ID of your OneUptime Project in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public projectId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "incidentId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Incident,
|
||||
title: "Incident",
|
||||
description: "Relation to Incident in which this resource belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Incident;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "incidentId" })
|
||||
public incident?: Incident = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
title: "Incident ID",
|
||||
description: "Relation to Incident ID in which this resource belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public incidentId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "createdByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
title: "Created by User",
|
||||
description:
|
||||
"Relation to User who created this object (if this object was created by a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "createdByUserId" })
|
||||
public createdByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Created by User ID",
|
||||
description:
|
||||
"User ID who created this object (if this object was created by a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public createdByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "deletedByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
title: "Deleted by User",
|
||||
description:
|
||||
"Relation to User who deleted this object (if this object was deleted by a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
cascade: false,
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "deletedByUserId" })
|
||||
public deletedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Deleted by User ID",
|
||||
description:
|
||||
"User ID who deleted this object (if this object was deleted by a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public deletedByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: true,
|
||||
title: "Log (in Markdown)",
|
||||
description: "Log of the entire incident state change in Markdown",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Markdown,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
})
|
||||
public feedInfoInMarkdown?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
title: "More Information (in Markdown)",
|
||||
description: "More information in Markdown",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Markdown,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public moreInformationInMarkdown?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ShortText,
|
||||
required: true,
|
||||
title: "Incident Feed Event",
|
||||
description: "Incident Feed Event",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ShortText,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
})
|
||||
public incidentFeedEventType?: IncidentFeedEventType = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateIncidentFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadIncidentFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Color,
|
||||
required: true,
|
||||
title: "Color",
|
||||
description: "Display color for the incident log",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Color,
|
||||
length: ColumnLength.Color,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
transformer: Color.getDatabaseTransformer(),
|
||||
})
|
||||
public displayColor?: Color = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "userId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
title: "User",
|
||||
description:
|
||||
"Relation to User who this feed belongs to (if this feed belongs to a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "userId" })
|
||||
public user?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "User ID",
|
||||
description:
|
||||
"User who this feed belongs to (if this feed belongs to a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public userId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
title: "Feed Posted At",
|
||||
description: "Date and time when the feed was posted",
|
||||
type: TableColumnType.Date,
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Date,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public postedAt?: Date = undefined;
|
||||
}
|
||||
@@ -507,7 +507,6 @@ export default class IncidentStateTimeline extends BaseModel {
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
|
||||
@@ -20,6 +20,7 @@ import GreenlockCertificate from "./GreenlockCertificate";
|
||||
import GreenlockChallenge from "./GreenlockChallenge";
|
||||
// Incidents
|
||||
import Incident from "./Incident";
|
||||
import IncidentFeed from "./IncidentFeed";
|
||||
import IncidentCustomField from "./IncidentCustomField";
|
||||
import IncidentInternalNote from "./IncidentInternalNote";
|
||||
import IncidentNoteTemplate from "./IncidentNoteTemplate";
|
||||
@@ -142,6 +143,7 @@ import ScheduledMaintenanceTemplateOwnerTeam from "./ScheduledMaintenanceTemplat
|
||||
import ScheduledMaintenanceTemplateOwnerUser from "./ScheduledMaintenanceTemplateOwnerUser";
|
||||
|
||||
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
|
||||
|
||||
import AlertState from "./AlertState";
|
||||
import Alert from "./Alert";
|
||||
import AlertCustomField from "./AlertCustomField";
|
||||
@@ -151,10 +153,13 @@ import AlertOwnerTeam from "./AlertOwnerTeam";
|
||||
import AlertOwnerUser from "./AlertOwnerUser";
|
||||
import AlertSeverity from "./AlertSeverity";
|
||||
import AlertNoteTemplate from "./AlertNoteTemplate";
|
||||
import AlertFeed from "./AlertFeed";
|
||||
|
||||
import TableView from "./TableView";
|
||||
import Dashboard from "./Dashboard";
|
||||
|
||||
import MonitorTest from "./MonitorTest";
|
||||
import ScheduledMaintenanceFeed from "./ScheduledMaintenanceFeed";
|
||||
|
||||
const AllModelTypes: Array<{
|
||||
new (): BaseModel;
|
||||
@@ -187,6 +192,7 @@ const AllModelTypes: Array<{
|
||||
|
||||
IncidentState,
|
||||
Incident,
|
||||
IncidentFeed,
|
||||
IncidentCustomField,
|
||||
IncidentStateTimeline,
|
||||
IncidentInternalNote,
|
||||
@@ -201,6 +207,7 @@ const AllModelTypes: Array<{
|
||||
|
||||
AlertState,
|
||||
Alert,
|
||||
AlertFeed,
|
||||
AlertCustomField,
|
||||
AlertStateTimeline,
|
||||
AlertInternalNote,
|
||||
@@ -232,6 +239,7 @@ const AllModelTypes: Array<{
|
||||
ScheduledMaintenancePublicNote,
|
||||
ScheduledMaintenanceInternalNote,
|
||||
ScheduledMaintenanceCustomField,
|
||||
ScheduledMaintenanceFeed,
|
||||
|
||||
BillingPaymentMethods,
|
||||
BillingInvoice,
|
||||
|
||||
@@ -455,7 +455,6 @@ export default class MonitorStatusTimeline extends BaseModel {
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
|
||||
@@ -216,6 +216,7 @@ export default class OnCallDutyPolicyExecutionLog extends BaseModel {
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Triggered By Incident ID",
|
||||
required: false,
|
||||
description:
|
||||
"ID of the incident which triggered this on-call escalation policy.",
|
||||
})
|
||||
@@ -270,6 +271,7 @@ export default class OnCallDutyPolicyExecutionLog extends BaseModel {
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Triggered By Alert ID",
|
||||
required: false,
|
||||
description:
|
||||
"ID of the incident which triggered this on-call escalation policy.",
|
||||
})
|
||||
|
||||
@@ -26,6 +26,7 @@ import OnCallDutyExecutionLogTimelineStatus from "../../Types/OnCallDutyPolicy/O
|
||||
import Permission from "../../Types/Permission";
|
||||
import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
||||
import Alert from "./Alert";
|
||||
|
||||
@TableBillingAccessControl({
|
||||
create: PlanType.Growth,
|
||||
@@ -216,18 +217,74 @@ export default class OnCallDutyPolicyExecutionLogTimeline extends BaseModel {
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
required: false,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Incident ID",
|
||||
description: "ID of your OneUptime Incident in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public triggeredByIncidentId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectOnCallDutyPolicyExecutionLogTimeline,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "triggeredByAlertId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Alert,
|
||||
title: "Alert",
|
||||
description: "Relation to Alert Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Alert;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "triggeredByAlertId" })
|
||||
public triggeredByAlert?: Alert = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectOnCallDutyPolicyExecutionLogTimeline,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: false,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Alert ID",
|
||||
description: "ID of your OneUptime Alert in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public triggeredByAlertId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [
|
||||
|
||||
530
Common/Models/DatabaseModels/ScheduledMaintenanceFeed.ts
Normal file
530
Common/Models/DatabaseModels/ScheduledMaintenanceFeed.ts
Normal file
@@ -0,0 +1,530 @@
|
||||
import ScheduledMaintenance from "./ScheduledMaintenance";
|
||||
import Project from "./Project";
|
||||
import User from "./User";
|
||||
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
|
||||
import Route from "../../Types/API/Route";
|
||||
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
|
||||
import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
|
||||
import CanAccessIfCanReadOn from "../../Types/Database/CanAccessIfCanReadOn";
|
||||
import ColumnType from "../../Types/Database/ColumnType";
|
||||
import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
|
||||
import EnableDocumentation from "../../Types/Database/EnableDocumentation";
|
||||
import EnableWorkflow from "../../Types/Database/EnableWorkflow";
|
||||
import TableColumn from "../../Types/Database/TableColumn";
|
||||
import TableColumnType from "../../Types/Database/TableColumnType";
|
||||
import TableMetadata from "../../Types/Database/TableMetadata";
|
||||
import TenantColumn from "../../Types/Database/TenantColumn";
|
||||
import IconProp from "../../Types/Icon/IconProp";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Permission from "../../Types/Permission";
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
||||
import ColumnLength from "../../Types/Database/ColumnLength";
|
||||
import Color from "../../Types/Color";
|
||||
|
||||
export enum ScheduledMaintenanceFeedEventType {
|
||||
PublicNote = "PublicNote",
|
||||
SubscriberNotificationSent = "SubscriberNotificationSent",
|
||||
OwnerNotificationSent = "OwnerNotificationSent",
|
||||
OwnerUserAdded = "OwnerUserAdded",
|
||||
OwnerTeamAdded = "OwnerTeamAdded",
|
||||
ScheduledMaintenanceCreated = "ScheduledMaintenanceCreated",
|
||||
ScheduledMaintenanceStateChanged = "ScheduledMaintenanceStateChanged",
|
||||
PrivateNote = "PrivateNote",
|
||||
ScheduledMaintenanceUpdated = "ScheduledMaintenanceUpdated",
|
||||
RootCause = "RootCause",
|
||||
RemediationNotes = "RemediationNotes",
|
||||
OwnerUserRemoved = "OwnerUserRemoved",
|
||||
OwnerTeamRemoved = "OwnerTeamRemoved",
|
||||
OnCallPolicy = "OnCallPolicy",
|
||||
OnCallNotification = "OnCallNotification",
|
||||
}
|
||||
|
||||
@EnableDocumentation()
|
||||
@CanAccessIfCanReadOn("scheduledMaintenance")
|
||||
@TenantColumn("projectId")
|
||||
@TableAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
delete: [],
|
||||
update: [],
|
||||
})
|
||||
@EnableWorkflow({
|
||||
create: true,
|
||||
delete: true,
|
||||
update: true,
|
||||
read: true,
|
||||
})
|
||||
@CrudApiEndpoint(new Route("/scheduled-maintenance-feed"))
|
||||
@Entity({
|
||||
name: "ScheduledMaintenanceFeed",
|
||||
})
|
||||
@TableMetadata({
|
||||
tableName: "ScheduledMaintenanceFeed",
|
||||
singularName: "Scheduled Maintenance Feed",
|
||||
pluralName: "Scheduled Maintenance Feed",
|
||||
icon: IconProp.List,
|
||||
tableDescription:
|
||||
"Log of the entire scheduled maintenance state change. This is a log of all the scheduled maintenance state changes, public notes, more etc.",
|
||||
})
|
||||
export default class ScheduledMaintenanceFeed extends BaseModel {
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "projectId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Project,
|
||||
title: "Project",
|
||||
description: "Relation to Project Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Project;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "projectId" })
|
||||
public project?: Project = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Project ID",
|
||||
description: "ID of your OneUptime Project in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public projectId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "scheduledMaintenanceId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: ScheduledMaintenance,
|
||||
title: "ScheduledMaintenance",
|
||||
description:
|
||||
"Relation to ScheduledMaintenance in which this resource belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return ScheduledMaintenance;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "scheduledMaintenanceId" })
|
||||
public scheduledMaintenance?: ScheduledMaintenance = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
title: "ScheduledMaintenance ID",
|
||||
description:
|
||||
"Relation to ScheduledMaintenance ID in which this resource belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public scheduledMaintenanceId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "createdByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
title: "Created by User",
|
||||
description:
|
||||
"Relation to User who created this object (if this object was created by a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "createdByUserId" })
|
||||
public createdByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Created by User ID",
|
||||
description:
|
||||
"User ID who created this object (if this object was created by a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public createdByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "deletedByUserId",
|
||||
type: TableColumnType.Entity,
|
||||
title: "Deleted by User",
|
||||
description:
|
||||
"Relation to User who deleted this object (if this object was deleted by a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
cascade: false,
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "deletedByUserId" })
|
||||
public deletedByUser?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Deleted by User ID",
|
||||
description:
|
||||
"User ID who deleted this object (if this object was deleted by a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public deletedByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: true,
|
||||
title: "Log (in Markdown)",
|
||||
description:
|
||||
"Log of the entire scheduled maintenance state change in Markdown",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Markdown,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
})
|
||||
public feedInfoInMarkdown?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Markdown,
|
||||
required: false,
|
||||
title: "More Information (in Markdown)",
|
||||
description: "More information in Markdown",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Markdown,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public moreInformationInMarkdown?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ShortText,
|
||||
required: true,
|
||||
title: "ScheduledMaintenance Log Event",
|
||||
description: "ScheduledMaintenance Log Event",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ShortText,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
})
|
||||
public scheduledMaintenanceFeedEventType?: ScheduledMaintenanceFeedEventType =
|
||||
undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Color,
|
||||
required: true,
|
||||
title: "Color",
|
||||
description: "Display color for this log",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Color,
|
||||
length: ColumnLength.Color,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
transformer: Color.getDatabaseTransformer(),
|
||||
})
|
||||
public displayColor?: Color = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "userId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: User,
|
||||
title: "User",
|
||||
description:
|
||||
"Relation to User who this feed belongs to (if this feed belongs to a User)",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return User;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "SET NULL",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "userId" })
|
||||
public user?: User = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "User ID",
|
||||
description:
|
||||
"User who this feed belongs to (if this feed belongs to a User)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public userId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateScheduledMaintenanceFeed,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceFeed,
|
||||
],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
title: "Feed Posted At",
|
||||
description: "Date and time when the feed was posted",
|
||||
type: TableColumnType.Date,
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Date,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public postedAt?: Date = undefined;
|
||||
}
|
||||
@@ -789,7 +789,12 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceTemplate,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditScheduledMaintenanceNoteTemplate,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: false,
|
||||
@@ -816,7 +821,12 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceTemplate,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditScheduledMaintenanceNoteTemplate,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: false,
|
||||
@@ -845,7 +855,12 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceTemplate,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditScheduledMaintenanceNoteTemplate,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: true,
|
||||
@@ -873,7 +888,12 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceTemplate,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditScheduledMaintenanceNoteTemplate,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: true,
|
||||
@@ -902,7 +922,12 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadScheduledMaintenanceTemplate,
|
||||
],
|
||||
update: [],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditScheduledMaintenanceNoteTemplate,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: true,
|
||||
|
||||
@@ -434,6 +434,63 @@ export default class StatusPageSubscriber extends BaseModel {
|
||||
})
|
||||
public deletedByUserId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateStatusPageSubscriber,
|
||||
Permission.Public,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadStatusPageSubscriber,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.EditStatusPageSubscriber,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: true,
|
||||
type: TableColumnType.Boolean,
|
||||
title: "Is Subscription Confirmed",
|
||||
description:
|
||||
"Has subscriber confirmed their subscription? (for example, by clicking on a confirmation link in an email)",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Boolean,
|
||||
default: false,
|
||||
})
|
||||
public isSubscriptionConfirmed?: boolean = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CreateStatusPageSubscriber,
|
||||
],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
isDefaultValueColumn: false,
|
||||
type: TableColumnType.ShortText,
|
||||
title: "Subscription Confirmation Token",
|
||||
description:
|
||||
"Token used to confirm subscription. This is a random token that is sent to the subscriber's email address to confirm their subscription.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ShortText,
|
||||
nullable: true,
|
||||
})
|
||||
public subscriptionConfirmationToken?: string = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
|
||||
@@ -221,14 +221,14 @@ export default class TelemetryException extends DatabaseBaseModel {
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
type: TableColumnType.LongText,
|
||||
type: TableColumnType.VeryLongText,
|
||||
canReadOnRelationQuery: false,
|
||||
title: "Exception Message",
|
||||
description: "Exception message that was thrown by the telemetry service",
|
||||
})
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: ColumnType.LongText,
|
||||
type: ColumnType.VeryLongText,
|
||||
})
|
||||
public message?: string = undefined;
|
||||
|
||||
@@ -252,7 +252,7 @@ export default class TelemetryException extends DatabaseBaseModel {
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
type: TableColumnType.LongText,
|
||||
type: TableColumnType.VeryLongText,
|
||||
canReadOnRelationQuery: false,
|
||||
title: "Stack Trace",
|
||||
description:
|
||||
@@ -260,7 +260,7 @@ export default class TelemetryException extends DatabaseBaseModel {
|
||||
})
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: ColumnType.LongText,
|
||||
type: ColumnType.VeryLongText,
|
||||
})
|
||||
public stackTrace?: string = undefined;
|
||||
|
||||
@@ -284,7 +284,7 @@ export default class TelemetryException extends DatabaseBaseModel {
|
||||
})
|
||||
@TableColumn({
|
||||
required: false,
|
||||
type: TableColumnType.LongText,
|
||||
type: TableColumnType.VeryLongText,
|
||||
canReadOnRelationQuery: false,
|
||||
title: "Exception Type",
|
||||
description:
|
||||
@@ -292,7 +292,7 @@ export default class TelemetryException extends DatabaseBaseModel {
|
||||
})
|
||||
@Column({
|
||||
nullable: true,
|
||||
type: ColumnType.LongText,
|
||||
type: ColumnType.VeryLongText,
|
||||
})
|
||||
public exceptionType?: string = undefined;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import IncidentSeverity from "./IncidentSeverity";
|
||||
import AlertSeverity from "./AlertSeverity";
|
||||
import Project from "./Project";
|
||||
import User from "./User";
|
||||
import UserCall from "./UserCall";
|
||||
@@ -450,6 +451,55 @@ class UserNotificationRule extends BaseModel {
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public incidentSeverityId?: ObjectID = undefined;
|
||||
|
||||
// alert severity.
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [Permission.CurrentUser],
|
||||
read: [Permission.CurrentUser],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "alertSeverityId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: AlertSeverity,
|
||||
title: "Alert Severity",
|
||||
description:
|
||||
"Relation to Alert Severity Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return AlertSeverity;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "alertSeverityId" })
|
||||
public alertSeverity?: AlertSeverity = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [Permission.CurrentUser],
|
||||
read: [Permission.CurrentUser],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: false,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Alert Severity ID",
|
||||
description: "ID of Alert Severity in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public alertSeverityId?: ObjectID = undefined;
|
||||
}
|
||||
|
||||
export default UserNotificationRule;
|
||||
|
||||
@@ -28,6 +28,7 @@ import Permission from "../../Types/Permission";
|
||||
import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
|
||||
import UserNotificationExecutionStatus from "../../Types/UserNotification/UserNotificationExecutionStatus";
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
||||
import Alert from "./Alert";
|
||||
|
||||
@EnableDocumentation()
|
||||
@TenantColumn("projectId")
|
||||
@@ -368,16 +369,62 @@ export default class UserOnCallLog extends BaseModel {
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Triggered By Incident ID",
|
||||
required: false,
|
||||
description:
|
||||
"ID of the incident which triggered this on-call escalation policy.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public triggeredByIncidentId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [Permission.CurrentUser],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "triggeredByAlertId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Alert,
|
||||
title: "Triggered By Alert",
|
||||
description: "Relation to Alert which triggered this on-call duty policy.",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Alert;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "triggeredByAlertId" })
|
||||
public triggeredByAlert?: Alert = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [Permission.CurrentUser],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
title: "Triggered By Alert ID",
|
||||
required: false,
|
||||
description:
|
||||
"ID of the Alert which triggered this on-call escalation policy.",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public triggeredByAlertId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [Permission.CurrentUser],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Incident from "./Incident";
|
||||
import Alert from "./Alert";
|
||||
import OnCallDutyPolicy from "./OnCallDutyPolicy";
|
||||
import OnCallDutyPolicyEscalationRule from "./OnCallDutyPolicyEscalationRule";
|
||||
import OnCallDutyPolicyExecutionLog from "./OnCallDutyPolicyExecutionLog";
|
||||
@@ -325,18 +326,64 @@ export default class UserOnCallLogTimeline extends BaseModel {
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: true,
|
||||
required: false,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Incident ID",
|
||||
description: "ID of your OneUptime Incident in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: false,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public triggeredByIncidentId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [Permission.CurrentUser],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
manyToOneRelationColumn: "triggeredByAlertId",
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Alert,
|
||||
title: "Alert",
|
||||
description: "Relation to Alert Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return Alert;
|
||||
},
|
||||
{
|
||||
eager: false,
|
||||
nullable: true,
|
||||
onDelete: "CASCADE",
|
||||
orphanedRowAction: "nullify",
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: "triggeredByAlertId" })
|
||||
public triggeredByAlert?: Alert = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [Permission.CurrentUser],
|
||||
update: [],
|
||||
})
|
||||
@Index()
|
||||
@TableColumn({
|
||||
type: TableColumnType.ObjectID,
|
||||
required: false,
|
||||
canReadOnRelationQuery: true,
|
||||
title: "Alert ID",
|
||||
description: "ID of your OneUptime Alert in which this object belongs",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.ObjectID,
|
||||
nullable: true,
|
||||
transformer: ObjectID.getDatabaseTransformer(),
|
||||
})
|
||||
public triggeredByAlertId?: ObjectID = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [Permission.CurrentUser],
|
||||
|
||||
@@ -291,6 +291,17 @@ export default class BaseAnalyticsAPI<
|
||||
) as any;
|
||||
}
|
||||
|
||||
let groupBy: GroupBy<AnalyticsDataModel> | null =
|
||||
req.body["groupBy"] || null;
|
||||
|
||||
if (groupBy && Object.keys(groupBy).length > 0) {
|
||||
groupBy = JSONFunctions.deserialize(groupBy as JSONObject) as any;
|
||||
}
|
||||
|
||||
if (groupBy && Object.keys(groupBy).length === 0) {
|
||||
groupBy = null;
|
||||
}
|
||||
|
||||
if (!aggregateBy) {
|
||||
throw new BadRequestException("AggregateBy is required");
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
import Response from "../Utils/Response";
|
||||
import BaseAPI from "./BaseAPI";
|
||||
import BaseModel from "Common/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
||||
import SubscriptionStatus from "Common/Types/Billing/SubscriptionStatus";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import { JSONObject } from "Common/Types/JSON";
|
||||
import Permission, { UserPermission } from "Common/Types/Permission";
|
||||
@@ -127,37 +126,8 @@ export default class UserAPI extends BaseAPI<
|
||||
},
|
||||
});
|
||||
|
||||
// refresh subscription status.
|
||||
const subscriptionState: SubscriptionStatus =
|
||||
await BillingService.getSubscriptionStatus(
|
||||
project.paymentProviderSubscriptionId as string,
|
||||
);
|
||||
|
||||
const meteredSubscriptionState: SubscriptionStatus =
|
||||
await BillingService.getSubscriptionStatus(
|
||||
project.paymentProviderMeteredSubscriptionId as string,
|
||||
);
|
||||
|
||||
// if subscription is cancelled, create a new subscription and update project.
|
||||
|
||||
if (
|
||||
meteredSubscriptionState === SubscriptionStatus.Canceled ||
|
||||
subscriptionState === SubscriptionStatus.Canceled
|
||||
) {
|
||||
await ProjectService.reactiveSubscription(project.id!);
|
||||
}
|
||||
|
||||
await ProjectService.updateOneById({
|
||||
id: project.id!,
|
||||
data: {
|
||||
paymentProviderSubscriptionStatus: subscriptionState,
|
||||
paymentProviderMeteredSubscriptionStatus:
|
||||
meteredSubscriptionState,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
ignoreHooks: true,
|
||||
},
|
||||
await BillingInvoiceService.refreshSubscriptionStatus({
|
||||
projectId: project.id!,
|
||||
});
|
||||
|
||||
return Response.sendEmptySuccessResponse(req, res);
|
||||
|
||||
@@ -13,7 +13,7 @@ import LIMIT_MAX from "Common/Types/Database/LimitMax";
|
||||
import PositiveNumber from "Common/Types/PositiveNumber";
|
||||
import Probe from "Common/Models/DatabaseModels/Probe";
|
||||
|
||||
export default class Ingestor extends BaseAPI<Probe, ProbeServiceType> {
|
||||
export default class ProbeAPI extends BaseAPI<Probe, ProbeServiceType> {
|
||||
public constructor() {
|
||||
super(Probe, ProbeService);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import BadRequestException from "../../Types/Exception/BadRequestException";
|
||||
import LocalCache from "../Infrastructure/LocalCache";
|
||||
import Express, {
|
||||
ExpressRequest,
|
||||
@@ -13,6 +14,9 @@ import ServerException from "Common/Types/Exception/ServerException";
|
||||
export interface StatusAPIOptions {
|
||||
readyCheck: () => Promise<void>;
|
||||
liveCheck: () => Promise<void>;
|
||||
globalCacheCheck?: (() => Promise<void>) | undefined;
|
||||
analyticsDatabaseCheck?: (() => Promise<void>) | undefined;
|
||||
databaseCheck?: (() => Promise<void>) | undefined;
|
||||
}
|
||||
|
||||
export default class StatusAPI {
|
||||
@@ -103,7 +107,7 @@ export default class StatusAPI {
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
try {
|
||||
logger.debug("Live check");
|
||||
await options.readyCheck();
|
||||
await options.liveCheck();
|
||||
logger.info("Live check: ok");
|
||||
stausLiveSuccess.add(1);
|
||||
|
||||
@@ -123,6 +127,94 @@ export default class StatusAPI {
|
||||
},
|
||||
);
|
||||
|
||||
// Global cache check
|
||||
router.get(
|
||||
"/status/global-cache",
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
try {
|
||||
logger.debug("Global cache check");
|
||||
if (options.globalCacheCheck) {
|
||||
await options.globalCacheCheck();
|
||||
} else {
|
||||
throw new BadRequestException("Global cache check not implemented");
|
||||
}
|
||||
logger.info("Global cache check: ok");
|
||||
|
||||
Response.sendJsonObjectResponse(req, res, {
|
||||
status: "ok",
|
||||
});
|
||||
} catch (e) {
|
||||
Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
e instanceof Exception
|
||||
? e
|
||||
: new ServerException("Global cache is not ready"),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Analytics database check
|
||||
router.get(
|
||||
"/status/analytics-database",
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
try {
|
||||
logger.debug("Analytics database check");
|
||||
if (options.analyticsDatabaseCheck) {
|
||||
await options.analyticsDatabaseCheck();
|
||||
} else {
|
||||
throw new BadRequestException(
|
||||
"Analytics database check not implemented",
|
||||
);
|
||||
}
|
||||
logger.info("Analytics database check: ok");
|
||||
|
||||
Response.sendJsonObjectResponse(req, res, {
|
||||
status: "ok",
|
||||
});
|
||||
} catch (e) {
|
||||
Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
e instanceof Exception
|
||||
? e
|
||||
: new ServerException("Analytics database is not ready"),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Database check
|
||||
router.get(
|
||||
"/status/database",
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
try {
|
||||
logger.debug("Database check");
|
||||
|
||||
if (options.databaseCheck) {
|
||||
await options.databaseCheck();
|
||||
} else {
|
||||
throw new BadRequestException("Database check not implemented");
|
||||
}
|
||||
|
||||
logger.info("Database check: ok");
|
||||
|
||||
Response.sendJsonObjectResponse(req, res, {
|
||||
status: "ok",
|
||||
});
|
||||
} catch (e) {
|
||||
Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
e instanceof Exception
|
||||
? e
|
||||
: new ServerException("Database is not ready"),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,66 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
public constructor() {
|
||||
super(StatusPage, StatusPageService);
|
||||
|
||||
// confirm subscription api
|
||||
this.router.get(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/confirm-subscription/:statusPageSubscriberId`,
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
const token: string = req.query["verification-token"] as string;
|
||||
|
||||
const statusPageSubscriberId: ObjectID = new ObjectID(
|
||||
req.params["statusPageSubscriberId"] as string,
|
||||
);
|
||||
|
||||
const subscriber: StatusPageSubscriber | null =
|
||||
await StatusPageSubscriberService.findOneBy({
|
||||
query: {
|
||||
_id: statusPageSubscriberId,
|
||||
subscriptionConfirmationToken: token,
|
||||
},
|
||||
select: {
|
||||
isSubscriptionConfirmed: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!subscriber) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException(
|
||||
"Subscriber not found or confirmation token is invalid",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// check if subscription confirmed already.
|
||||
|
||||
if (subscriber.isSubscriptionConfirmed) {
|
||||
return Response.sendEmptySuccessResponse(req, res);
|
||||
}
|
||||
|
||||
await StatusPageSubscriberService.updateOneById({
|
||||
id: statusPageSubscriberId,
|
||||
data: {
|
||||
isSubscriptionConfirmed: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
await StatusPageSubscriberService.sendYouHaveSubscribedEmail({
|
||||
subscriberId: statusPageSubscriberId,
|
||||
});
|
||||
|
||||
return Response.sendEmptySuccessResponse(req, res);
|
||||
},
|
||||
);
|
||||
|
||||
// CNAME verification api
|
||||
this.router.get(
|
||||
`${new this.entityType()
|
||||
@@ -1033,7 +1093,18 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
},
|
||||
});
|
||||
|
||||
const overallStatus: MonitorStatus | null =
|
||||
this.getOverallMonitorStatus(
|
||||
statusPageResources,
|
||||
monitorStatuses,
|
||||
monitorGroupCurrentStatuses,
|
||||
);
|
||||
|
||||
const response: JSONObject = {
|
||||
overallStatus: overallStatus
|
||||
? BaseModel.toJSON(overallStatus, MonitorStatus)
|
||||
: null,
|
||||
|
||||
scheduledMaintenanceEventsPublicNotes: BaseModel.toJSONArray(
|
||||
scheduledMaintenanceEventsPublicNotes,
|
||||
ScheduledMaintenancePublicNote,
|
||||
@@ -2224,4 +2295,54 @@ export default class StatusPageAPI extends BaseAPI<
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public getOverallMonitorStatus(
|
||||
statusPageResources: Array<StatusPageResource>,
|
||||
monitorStatuses: Array<MonitorStatus>,
|
||||
monitorGroupCurrentStatuses: Dictionary<ObjectID>,
|
||||
): MonitorStatus | null {
|
||||
let currentStatus: MonitorStatus | null =
|
||||
monitorStatuses.length > 0 && monitorStatuses[0]
|
||||
? monitorStatuses[0]
|
||||
: null;
|
||||
|
||||
const dict: Dictionary<number> = {};
|
||||
|
||||
for (const resource of statusPageResources) {
|
||||
if (resource.monitor?.currentMonitorStatusId) {
|
||||
if (
|
||||
!Object.keys(dict).includes(
|
||||
resource.monitor?.currentMonitorStatusId.toString() || "",
|
||||
)
|
||||
) {
|
||||
dict[resource.monitor?.currentMonitorStatusId?.toString()] = 1;
|
||||
} else {
|
||||
dict[resource.monitor!.currentMonitorStatusId!.toString()]!++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check status of monitor groups.
|
||||
|
||||
for (const groupId in monitorGroupCurrentStatuses) {
|
||||
const statusId: ObjectID | undefined =
|
||||
monitorGroupCurrentStatuses[groupId];
|
||||
|
||||
if (statusId) {
|
||||
if (!Object.keys(dict).includes(statusId.toString() || "")) {
|
||||
dict[statusId.toString()] = 1;
|
||||
} else {
|
||||
dict[statusId.toString()]!++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const monitorStatus of monitorStatuses) {
|
||||
if (monitorStatus._id && dict[monitorStatus._id]) {
|
||||
currentStatus = monitorStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return currentStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ export default class UserNotificationLogTimelineAPI extends BaseAPI<
|
||||
_id: true,
|
||||
projectId: true,
|
||||
triggeredByIncidentId: true,
|
||||
triggeredByAlertId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
@@ -115,6 +116,7 @@ export default class UserNotificationLogTimelineAPI extends BaseAPI<
|
||||
_id: true,
|
||||
projectId: true,
|
||||
triggeredByIncidentId: true,
|
||||
triggeredByAlertId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
@@ -147,16 +149,38 @@ export default class UserNotificationLogTimelineAPI extends BaseAPI<
|
||||
const host: Hostname = await DatabaseConfig.getHost();
|
||||
const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
|
||||
|
||||
return Response.redirect(
|
||||
if (timelineItem.triggeredByIncidentId) {
|
||||
return Response.redirect(
|
||||
req,
|
||||
res,
|
||||
new URL(
|
||||
httpProtocol,
|
||||
host,
|
||||
DashboardRoute.addRoute(
|
||||
`/${timelineItem.projectId?.toString()}/incidents/${timelineItem.triggeredByIncidentId!.toString()}`,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (timelineItem.triggeredByAlertId) {
|
||||
return Response.redirect(
|
||||
req,
|
||||
res,
|
||||
new URL(
|
||||
httpProtocol,
|
||||
host,
|
||||
DashboardRoute.addRoute(
|
||||
`/${timelineItem.projectId?.toString()}/alerts/${timelineItem.triggeredByAlertId!.toString()}`,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new URL(
|
||||
httpProtocol,
|
||||
host,
|
||||
DashboardRoute.addRoute(
|
||||
`/${timelineItem.projectId?.toString()}/incidents/${timelineItem.triggeredByIncidentId!.toString()}`,
|
||||
),
|
||||
),
|
||||
new BadDataException("Invalid item Id"),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@ export enum ConfigLogLevel {
|
||||
WARN = "WARN",
|
||||
ERROR = "ERROR",
|
||||
DEBUG = "DEBUG",
|
||||
OFF = "OFF",
|
||||
}
|
||||
|
||||
export const getAllEnvVars: () => JSONObject = (): JSONObject => {
|
||||
@@ -88,9 +89,27 @@ export const AppApiHostname: Hostname = Hostname.fromString(
|
||||
}`,
|
||||
);
|
||||
|
||||
export const IngestorHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_INGESTOR_HOSTNAME"] || "localhost"}:${
|
||||
process.env["INGESTOR_PORT"] || 80
|
||||
export const ProbeIngestHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_PROBE_INGEST_HOSTNAME"] || "localhost"}:${
|
||||
process.env["PROBE_INGEST_PORT"] || 80
|
||||
}`,
|
||||
);
|
||||
|
||||
export const OpenTelemetryIngestHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_OPEN_TELEMETRY_INGEST_HOSTNAME"] || "localhost"}:${
|
||||
process.env["OPEN_TELEMETRY_INGEST_PORT"] || 80
|
||||
}`,
|
||||
);
|
||||
|
||||
export const IncomingRequestIngestHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_INCOMING_REQUEST_INGEST_HOSTNAME"] || "localhost"}:${
|
||||
process.env["INCOMING_REQUEST_INGEST_PORT"] || 80
|
||||
}`,
|
||||
);
|
||||
|
||||
export const FluentIngestHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_FLUENT_INGEST_HOSTNAME"] || "localhost"}:${
|
||||
process.env["FLUENT_INGEST_PORT"] || 80
|
||||
}`,
|
||||
);
|
||||
|
||||
@@ -162,6 +181,10 @@ export const ShouldRedisTlsEnable: boolean = Boolean(
|
||||
RedisTlsCa || (RedisTlsCert && RedisTlsKey),
|
||||
);
|
||||
|
||||
export const RedisIPFamily: number = process.env["REDIS_IP_FAMILY"]
|
||||
? Number(process.env["REDIS_IP_FAMILY"])
|
||||
: 4;
|
||||
|
||||
export const IsProduction: boolean =
|
||||
process.env["ENVIRONMENT"] === "production";
|
||||
|
||||
@@ -179,6 +202,9 @@ export const AnalyticsHost: string = process.env["ANALYTICS_HOST"] || "";
|
||||
export const DisableAutomaticIncidentCreation: boolean =
|
||||
process.env["DISABLE_AUTOMATIC_INCIDENT_CREATION"] === "true";
|
||||
|
||||
export const DisableAutomaticAlertCreation: boolean =
|
||||
process.env["DISABLE_AUTOMATIC_ALERT_CREATION"] === "true";
|
||||
|
||||
export const ClickhouseHost: Hostname = Hostname.fromString(
|
||||
process.env["CLICKHOUSE_HOST"] || "clickhouse",
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { NodeClickHouseClientConfigOptions } from "@clickhouse/client/dist/config";
|
||||
import {
|
||||
ClickHouseIsHostHttps,
|
||||
ClickhouseDatabase,
|
||||
@@ -10,14 +11,17 @@ import {
|
||||
ClickhouseUsername,
|
||||
ShouldClickhouseSslEnable,
|
||||
} from "../EnvironmentConfig";
|
||||
import { NodeClickHouseClientConfigOptions } from "@clickhouse/client/dist/client";
|
||||
import Hostname from "../../Types/API/Hostname";
|
||||
|
||||
export type ClickHouseClientConfigOptions = NodeClickHouseClientConfigOptions;
|
||||
|
||||
const hostProtocol: string = ClickHouseIsHostHttps ? "https" : "http";
|
||||
|
||||
const clickhouseHost: Hostname = ClickhouseHost || new Hostname("clickhouse");
|
||||
const clickhousePort: string = (ClickhousePort || 8123).toString();
|
||||
|
||||
const options: ClickHouseClientConfigOptions = {
|
||||
host: `${hostProtocol}://${ClickhouseHost.toString()}:${ClickhousePort.toNumber()}`,
|
||||
url: `${hostProtocol}://${clickhouseHost.toString()}:${clickhousePort}`,
|
||||
username: ClickhouseUsername,
|
||||
password: ClickhousePassword,
|
||||
database: ClickhouseDatabase,
|
||||
|
||||
@@ -4,12 +4,16 @@ import {
|
||||
dataSourceOptions,
|
||||
testDataSourceOptions,
|
||||
} from "./ClickhouseConfig";
|
||||
import { ClickHouseClient, PingResult, createClient } from "@clickhouse/client";
|
||||
import { PingResult, createClient, ClickHouseClient } from "@clickhouse/client";
|
||||
import DatabaseNotConnectedException from "Common/Types/Exception/DatabaseNotConnectedException";
|
||||
import Sleep from "Common/Types/Sleep";
|
||||
import Stream from "stream";
|
||||
import API from "../../Utils/API";
|
||||
import URL from "../../Types/API/URL";
|
||||
import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
|
||||
import HTTPResponse from "../../Types/API/HTTPResponse";
|
||||
import { JSONObject } from "../../Types/JSON";
|
||||
|
||||
export type ClickhouseClient = ClickHouseClient<Stream.Readable>;
|
||||
export type ClickhouseClient = ClickHouseClient;
|
||||
|
||||
export default class ClickhouseDatabase {
|
||||
private dataSource!: ClickhouseClient | null;
|
||||
@@ -101,7 +105,23 @@ export default class ClickhouseDatabase {
|
||||
public async checkConnnectionStatus(): Promise<boolean> {
|
||||
// Ping clickhouse to check if the connection is still alive
|
||||
try {
|
||||
const result: PingResult | undefined = await this.getDataSource()?.ping();
|
||||
logger.debug(
|
||||
"Checking Clickhouse Connection Status - pinging clickhouse",
|
||||
);
|
||||
|
||||
const dbUrl: string | undefined = this.getDatasourceOptions().url as
|
||||
| string
|
||||
| undefined;
|
||||
|
||||
if (!dbUrl) {
|
||||
throw new DatabaseNotConnectedException("Clickhouse URL not found");
|
||||
}
|
||||
|
||||
const result: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
||||
await API.get(URL.fromString(dbUrl.toString()));
|
||||
|
||||
logger.debug("Clickhouse Connection Status Result");
|
||||
logger.debug(result);
|
||||
|
||||
if (!result) {
|
||||
throw new DatabaseNotConnectedException(
|
||||
@@ -109,13 +129,24 @@ export default class ClickhouseDatabase {
|
||||
);
|
||||
}
|
||||
|
||||
if (result?.success === false) {
|
||||
if (result instanceof HTTPErrorResponse) {
|
||||
throw new DatabaseNotConnectedException(
|
||||
"Clickhouse Database is not connected",
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
if (
|
||||
result.data &&
|
||||
((result.data as JSONObject)["data"] as string) &&
|
||||
((result.data as JSONObject)["data"] as string).toString().trim() ===
|
||||
"Ok."
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new DatabaseNotConnectedException(
|
||||
"Clickhouse Database is not connected",
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error("Clickhouse Connection Lost");
|
||||
logger.error(err);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1731433043136 implements MigrationInterface {
|
||||
public name = "MigrationName1731433043136";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_5218e92f700d91afe6a8db79cb"`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_5218e92f700d91afe6a8db79cb" ON "Incident" ("rootCause") `,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1731433309124 implements MigrationInterface {
|
||||
public name = "MigrationName1731433309124";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_fc40ea6a9ad55f29bca4f4a15d"`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_fc40ea6a9ad55f29bca4f4a15d" ON "Alert" ("rootCause") `,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1731435267537 implements MigrationInterface {
|
||||
public name = "MigrationName1731435267537";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_01ac1d1ef9e72aeb6dac6575dd"`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_01ac1d1ef9e72aeb6dac6575dd" ON "MonitorStatusTimeline" ("rootCause") `,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1731435514287 implements MigrationInterface {
|
||||
public name = "MigrationName1731435514287";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_7db6b1a8fbbc9eb44c2e7f5047"`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_7db6b1a8fbbc9eb44c2e7f5047" ON "IncidentStateTimeline" ("rootCause") `,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1732553444010 implements MigrationInterface {
|
||||
public name = "MigrationName1732553444010";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ALTER COLUMN "message" TYPE text`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ALTER COLUMN "stackTrace" TYPE text`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ALTER COLUMN "exceptionType" TYPE text`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
// revert changes made in up method - text to varchar
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ALTER COLUMN "message" TYPE varchar`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ALTER COLUMN "stackTrace" TYPE varchar`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "TelemetryException" ALTER COLUMN "exceptionType" TYPE varchar`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1734435866602 implements MigrationInterface {
|
||||
public name = "MigrationName1734435866602";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPageSubscriber" ADD "isSubscriptionConfirmed" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPageSubscriber" ADD "subscriptionConfirmationToken" character varying`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "subscriptionConfirmationToken"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPageSubscriber" DROP COLUMN "isSubscriptionConfirmed"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736364478985 implements MigrationInterface {
|
||||
public name = "MigrationName1736364478985";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "IncidentLog" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "incidentId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "logInMarkdown" text NOT NULL, "moreInformationInMarkdown" text NOT NULL, "incidentLogEvent" character varying NOT NULL, CONSTRAINT "PK_947cb9f32cf204561d10d64adeb" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_855797e41af7d35b18a7f3f97b" ON "IncidentLog" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_1eff2f3d075754ef9c16e8b962" ON "IncidentLog" ("incidentId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" ADD CONSTRAINT "FK_855797e41af7d35b18a7f3f97bd" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" ADD CONSTRAINT "FK_1eff2f3d075754ef9c16e8b962c" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" ADD CONSTRAINT "FK_da6bb8bf63b18a7ddc35cc2901a" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" ADD CONSTRAINT "FK_bb1b8b83ffdfc702088b74f2e16" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" DROP CONSTRAINT "FK_bb1b8b83ffdfc702088b74f2e16"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" DROP CONSTRAINT "FK_da6bb8bf63b18a7ddc35cc2901a"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" DROP CONSTRAINT "FK_1eff2f3d075754ef9c16e8b962c"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" DROP CONSTRAINT "FK_855797e41af7d35b18a7f3f97bd"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_1eff2f3d075754ef9c16e8b962"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_855797e41af7d35b18a7f3f97b"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "IncidentLog"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736364957990 implements MigrationInterface {
|
||||
public name = "MigrationName1736364957990";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "AlertLog" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "alertId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "logInMarkdown" text NOT NULL, "moreInformationInMarkdown" text NOT NULL, "alertLogEvent" character varying NOT NULL, CONSTRAINT "PK_500826238fa54528b0026f55d47" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_d5d56f9ed2c4c72745372a1ac6" ON "AlertLog" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_52bbabed66e4e728441d49478f" ON "AlertLog" ("alertId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" ADD CONSTRAINT "FK_d5d56f9ed2c4c72745372a1ac6f" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" ADD CONSTRAINT "FK_52bbabed66e4e728441d49478f8" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" ADD CONSTRAINT "FK_f5f832aad105579e95a09e1ddd0" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" ADD CONSTRAINT "FK_7ca9046915f6de6e7a199588d26" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" DROP CONSTRAINT "FK_7ca9046915f6de6e7a199588d26"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" DROP CONSTRAINT "FK_f5f832aad105579e95a09e1ddd0"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" DROP CONSTRAINT "FK_52bbabed66e4e728441d49478f8"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" DROP CONSTRAINT "FK_d5d56f9ed2c4c72745372a1ac6f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_52bbabed66e4e728441d49478f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_d5d56f9ed2c4c72745372a1ac6"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "AlertLog"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736365532085 implements MigrationInterface {
|
||||
public name = "MigrationName1736365532085";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "ScheduledMaintenanceLog" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "scheduledMaintenanceId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "logInMarkdown" text NOT NULL, "moreInformationInMarkdown" text NOT NULL, "scheduledMaintenanceLogEvent" character varying NOT NULL, CONSTRAINT "PK_27b89f28bf48418fabba9a1ea14" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_9239de1ee33f9505c30f255a99" ON "ScheduledMaintenanceLog" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_58e403ba261dfa94addb5f04d3" ON "ScheduledMaintenanceLog" ("scheduledMaintenanceId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" ADD CONSTRAINT "FK_9239de1ee33f9505c30f255a994" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" ADD CONSTRAINT "FK_58e403ba261dfa94addb5f04d36" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" ADD CONSTRAINT "FK_9152528e4f7f59adaba3e9bc41f" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" ADD CONSTRAINT "FK_a957f435d1504f41808f20a2c45" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" DROP CONSTRAINT "FK_a957f435d1504f41808f20a2c45"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" DROP CONSTRAINT "FK_9152528e4f7f59adaba3e9bc41f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" DROP CONSTRAINT "FK_58e403ba261dfa94addb5f04d36"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" DROP CONSTRAINT "FK_9239de1ee33f9505c30f255a994"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_58e403ba261dfa94addb5f04d3"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_9239de1ee33f9505c30f255a99"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "ScheduledMaintenanceLog"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736675947746 implements MigrationInterface {
|
||||
public name = "MigrationName1736675947746";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Incident" ADD "incidentNumber" integer`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_0eca9ce7d12a4c472386dfc781" ON "Incident" ("incidentNumber") `,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_0eca9ce7d12a4c472386dfc781"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Incident" DROP COLUMN "incidentNumber"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736703138918 implements MigrationInterface {
|
||||
public name = "MigrationName1736703138918";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" ADD "incidentLogSeverity" character varying NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" ADD "alertLogSeverity" character varying NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" ADD "scheduledMaintenanceLogSeverity" character varying NOT NULL`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceLog" DROP COLUMN "scheduledMaintenanceLogSeverity"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertLog" DROP COLUMN "alertLogSeverity"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentLog" DROP COLUMN "incidentLogSeverity"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736780194077 implements MigrationInterface {
|
||||
public name = "MigrationName1736780194077";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "IncidentFeed" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "incidentId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "feedInfoInMarkdown" text NOT NULL, "moreInformationInMarkdown" text NOT NULL, "incidentFeedEventType" character varying NOT NULL, "displayColor" character varying(7) NOT NULL, CONSTRAINT "PK_8188c79d1ed22013205ff324dea" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_32ae47fa45018ecdb7f28c6468" ON "IncidentFeed" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_cf4aea7310bb855873fc40f244" ON "IncidentFeed" ("incidentId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "AlertFeed" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "alertId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "feedInfoInMarkdown" text NOT NULL, "moreInformationInMarkdown" text NOT NULL, "alertFeedEventType" character varying NOT NULL, "displayColor" character varying(7) NOT NULL, CONSTRAINT "PK_d5f629abd40a51d58a35423b361" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_f430519f21c327c14c12e4f106" ON "AlertFeed" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_f74177b6675d92243cc0794bd3" ON "AlertFeed" ("alertId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "ScheduledMaintenanceFeed" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "scheduledMaintenanceId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "feedInfoInMarkdown" text NOT NULL, "moreInformationInMarkdown" text NOT NULL, "scheduledMaintenanceFeedEventType" character varying NOT NULL, "displayColor" character varying(7) NOT NULL, CONSTRAINT "PK_ced33ccb5551624e432b2df6513" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_416c6ded7f17b15e9a83114740" ON "ScheduledMaintenanceFeed" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_ce3b353bbd3e1695c0ffb2d235" ON "ScheduledMaintenanceFeed" ("scheduledMaintenanceId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ADD CONSTRAINT "FK_32ae47fa45018ecdb7f28c64685" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ADD CONSTRAINT "FK_cf4aea7310bb855873fc40f2441" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ADD CONSTRAINT "FK_4458fd00d52521ae4333e74ddbd" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ADD CONSTRAINT "FK_f1ee9faba64e96f91925247aae3" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ADD CONSTRAINT "FK_f430519f21c327c14c12e4f1063" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ADD CONSTRAINT "FK_f74177b6675d92243cc0794bd3f" FOREIGN KEY ("alertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ADD CONSTRAINT "FK_2eda7dbbc78de28f653812b5e3d" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ADD CONSTRAINT "FK_f0e72673c38f18ed84f0e94a5a1" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD CONSTRAINT "FK_416c6ded7f17b15e9a831147403" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD CONSTRAINT "FK_ce3b353bbd3e1695c0ffb2d2354" FOREIGN KEY ("scheduledMaintenanceId") REFERENCES "ScheduledMaintenance"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD CONSTRAINT "FK_fc34cf1a5eb488310bbe7c6a46a" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD CONSTRAINT "FK_8374052884c5d75f5018c1dc908" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP CONSTRAINT "FK_8374052884c5d75f5018c1dc908"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP CONSTRAINT "FK_fc34cf1a5eb488310bbe7c6a46a"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP CONSTRAINT "FK_ce3b353bbd3e1695c0ffb2d2354"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP CONSTRAINT "FK_416c6ded7f17b15e9a831147403"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" DROP CONSTRAINT "FK_f0e72673c38f18ed84f0e94a5a1"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" DROP CONSTRAINT "FK_2eda7dbbc78de28f653812b5e3d"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" DROP CONSTRAINT "FK_f74177b6675d92243cc0794bd3f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" DROP CONSTRAINT "FK_f430519f21c327c14c12e4f1063"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" DROP CONSTRAINT "FK_f1ee9faba64e96f91925247aae3"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" DROP CONSTRAINT "FK_4458fd00d52521ae4333e74ddbd"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" DROP CONSTRAINT "FK_cf4aea7310bb855873fc40f2441"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" DROP CONSTRAINT "FK_32ae47fa45018ecdb7f28c64685"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_ce3b353bbd3e1695c0ffb2d235"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_416c6ded7f17b15e9a83114740"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "ScheduledMaintenanceFeed"`);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_f74177b6675d92243cc0794bd3"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_f430519f21c327c14c12e4f106"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "AlertFeed"`);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_cf4aea7310bb855873fc40f244"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_32ae47fa45018ecdb7f28c6468"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "IncidentFeed"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736780194078 implements MigrationInterface {
|
||||
public name = "MigrationName1736780194078";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// drop tables IncidentLog, AlertLog, ScheduledMaintenanceLog
|
||||
await queryRunner.query(`DROP TABLE "IncidentLog"`);
|
||||
await queryRunner.query(`DROP TABLE "AlertLog"`);
|
||||
await queryRunner.query(`DROP TABLE "ScheduledMaintenanceLog"`);
|
||||
}
|
||||
|
||||
public async down(_queryRunner: QueryRunner): Promise<void> {
|
||||
// do nothing.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736787495707 implements MigrationInterface {
|
||||
public name = "MigrationName1736787495707";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ALTER COLUMN "moreInformationInMarkdown" DROP NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ALTER COLUMN "moreInformationInMarkdown" DROP NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ALTER COLUMN "moreInformationInMarkdown" DROP NOT NULL`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ALTER COLUMN "moreInformationInMarkdown" SET NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ALTER COLUMN "moreInformationInMarkdown" SET NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ALTER COLUMN "moreInformationInMarkdown" SET NOT NULL`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736787985322 implements MigrationInterface {
|
||||
public name = "MigrationName1736787985322";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Label" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentSeverity" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentState" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "MonitorStatus" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ALTER COLUMN "displayColor" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertSeverity" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertState" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceState" ALTER COLUMN "color" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPage" ALTER COLUMN "defaultBarColor" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPageHistoryChartBarColorRule" ALTER COLUMN "barColor" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ALTER COLUMN "displayColor" TYPE character varying(10)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ALTER COLUMN "displayColor" TYPE character varying(10)`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Label" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentSeverity" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentState" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "MonitorStatus" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ALTER COLUMN "displayColor" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertSeverity" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertState" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceState" ALTER COLUMN "color" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPage" ALTER COLUMN "defaultBarColor" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPageHistoryChartBarColorRule" ALTER COLUMN "barColor" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ALTER COLUMN "displayColor" TYPE character varying(7)`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ALTER COLUMN "displayColor" TYPE character varying(7)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736788706141 implements MigrationInterface {
|
||||
public name = "MigrationName1736788706141";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "IncidentFeed" ADD "userId" uuid`);
|
||||
await queryRunner.query(`ALTER TABLE "AlertFeed" ADD "userId" uuid`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD "userId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ADD CONSTRAINT "FK_010577090e59583da93c867f541" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ADD CONSTRAINT "FK_97b19fbc90b6105614cc0cba300" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD CONSTRAINT "FK_541c2b40579cbf342c8850ced2b" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP CONSTRAINT "FK_541c2b40579cbf342c8850ced2b"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" DROP CONSTRAINT "FK_97b19fbc90b6105614cc0cba300"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" DROP CONSTRAINT "FK_010577090e59583da93c867f541"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP COLUMN "userId"`,
|
||||
);
|
||||
await queryRunner.query(`ALTER TABLE "AlertFeed" DROP COLUMN "userId"`);
|
||||
await queryRunner.query(`ALTER TABLE "IncidentFeed" DROP COLUMN "userId"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1736856662868 implements MigrationInterface {
|
||||
public name = "MigrationName1736856662868";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" ADD "postedAt" TIMESTAMP WITH TIME ZONE`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "AlertFeed" ADD "postedAt" TIMESTAMP WITH TIME ZONE`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" ADD "postedAt" TIMESTAMP WITH TIME ZONE`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "ScheduledMaintenanceFeed" DROP COLUMN "postedAt"`,
|
||||
);
|
||||
await queryRunner.query(`ALTER TABLE "AlertFeed" DROP COLUMN "postedAt"`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "IncidentFeed" DROP COLUMN "postedAt"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1737141420441 implements MigrationInterface {
|
||||
public name = "MigrationName1737141420441";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" ADD "triggeredByAlertId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserNotificationRule" ADD "alertSeverityId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" ADD "triggeredByAlertId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" ADD "triggeredByAlertId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" DROP CONSTRAINT "FK_90119ec7f77fa2efd82261e0448"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" ALTER COLUMN "triggeredByIncidentId" DROP NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" DROP CONSTRAINT "FK_eeb0dd05d1dec542c3de5fb5074"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" ALTER COLUMN "triggeredByIncidentId" DROP NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" DROP CONSTRAINT "FK_58a44736718a5ec4fe41526289a"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" ALTER COLUMN "triggeredByIncidentId" DROP NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_30358ab25e4c6c9ad72e74f201" ON "OnCallDutyPolicyExecutionLogTimeline" ("triggeredByAlertId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_d73339f6c26fd6ebd0326badcd" ON "UserNotificationRule" ("alertSeverityId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_42d9916277fcbefa0cdd3904c6" ON "UserOnCallLogTimeline" ("triggeredByAlertId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" ADD CONSTRAINT "FK_90119ec7f77fa2efd82261e0448" FOREIGN KEY ("triggeredByIncidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" ADD CONSTRAINT "FK_30358ab25e4c6c9ad72e74f201c" FOREIGN KEY ("triggeredByAlertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserNotificationRule" ADD CONSTRAINT "FK_d73339f6c26fd6ebd0326badcd7" FOREIGN KEY ("alertSeverityId") REFERENCES "AlertSeverity"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" ADD CONSTRAINT "FK_eeb0dd05d1dec542c3de5fb5074" FOREIGN KEY ("triggeredByIncidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" ADD CONSTRAINT "FK_0ee3711cdc64957845d9d028c31" FOREIGN KEY ("triggeredByAlertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" ADD CONSTRAINT "FK_58a44736718a5ec4fe41526289a" FOREIGN KEY ("triggeredByIncidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" ADD CONSTRAINT "FK_42d9916277fcbefa0cdd3904c63" FOREIGN KEY ("triggeredByAlertId") REFERENCES "Alert"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" DROP CONSTRAINT "FK_42d9916277fcbefa0cdd3904c63"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" DROP CONSTRAINT "FK_58a44736718a5ec4fe41526289a"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" DROP CONSTRAINT "FK_0ee3711cdc64957845d9d028c31"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" DROP CONSTRAINT "FK_eeb0dd05d1dec542c3de5fb5074"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserNotificationRule" DROP CONSTRAINT "FK_d73339f6c26fd6ebd0326badcd7"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" DROP CONSTRAINT "FK_30358ab25e4c6c9ad72e74f201c"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" DROP CONSTRAINT "FK_90119ec7f77fa2efd82261e0448"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_42d9916277fcbefa0cdd3904c6"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_d73339f6c26fd6ebd0326badcd"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_30358ab25e4c6c9ad72e74f201"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" ALTER COLUMN "triggeredByIncidentId" SET NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" ADD CONSTRAINT "FK_58a44736718a5ec4fe41526289a" FOREIGN KEY ("triggeredByIncidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" ALTER COLUMN "triggeredByIncidentId" SET NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" ADD CONSTRAINT "FK_eeb0dd05d1dec542c3de5fb5074" FOREIGN KEY ("triggeredByIncidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" ALTER COLUMN "triggeredByIncidentId" SET NOT NULL`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" ADD CONSTRAINT "FK_90119ec7f77fa2efd82261e0448" FOREIGN KEY ("triggeredByIncidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLogTimeline" DROP COLUMN "triggeredByAlertId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserOnCallLog" DROP COLUMN "triggeredByAlertId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "UserNotificationRule" DROP COLUMN "alertSeverityId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyExecutionLogTimeline" DROP COLUMN "triggeredByAlertId"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,24 @@ import { MigrationName1729682875503 } from "./1729682875503-MigrationName";
|
||||
import { MigrationName1730117995642 } from "./1730117995642-MigrationName";
|
||||
import { MigrationName1730209089495 } from "./1730209089495-MigrationName";
|
||||
import { MigrationName1730223198692 } from "./1730223198692-MigrationName";
|
||||
import { MigrationName1731433043136 } from "./1731433043136-MigrationName";
|
||||
import { MigrationName1731433309124 } from "./1731433309124-MigrationName";
|
||||
import { MigrationName1731435267537 } from "./1731435267537-MigrationName";
|
||||
import { MigrationName1731435514287 } from "./1731435514287-MigrationName";
|
||||
import { MigrationName1732553444010 } from "./1732553444010-MigrationName";
|
||||
import { MigrationName1734435866602 } from "./1734435866602-MigrationName";
|
||||
import { MigrationName1736364478985 } from "./1736364478985-MigrationName";
|
||||
import { MigrationName1736364957990 } from "./1736364957990-MigrationName";
|
||||
import { MigrationName1736365532085 } from "./1736365532085-MigrationName";
|
||||
import { MigrationName1736675947746 } from "./1736675947746-MigrationName";
|
||||
import { MigrationName1736703138918 } from "./1736703138918-MigrationName";
|
||||
import { MigrationName1736780194077 } from "./1736780194077-MigrationName";
|
||||
import { MigrationName1736780194078 } from "./1736780194078-MigrationName";
|
||||
import { MigrationName1736787495707 } from "./1736787495707-MigrationName";
|
||||
import { MigrationName1736787985322 } from "./1736787985322-MigrationName";
|
||||
import { MigrationName1736788706141 } from "./1736788706141-MigrationName";
|
||||
import { MigrationName1736856662868 } from "./1736856662868-MigrationName";
|
||||
import { MigrationName1737141420441 } from "./1737141420441-MigrationName";
|
||||
|
||||
export default [
|
||||
InitialMigration,
|
||||
@@ -160,4 +178,22 @@ export default [
|
||||
MigrationName1730117995642,
|
||||
MigrationName1730209089495,
|
||||
MigrationName1730223198692,
|
||||
MigrationName1731433043136,
|
||||
MigrationName1731433309124,
|
||||
MigrationName1731435267537,
|
||||
MigrationName1731435514287,
|
||||
MigrationName1732553444010,
|
||||
MigrationName1734435866602,
|
||||
MigrationName1736364478985,
|
||||
MigrationName1736364957990,
|
||||
MigrationName1736365532085,
|
||||
MigrationName1736675947746,
|
||||
MigrationName1736703138918,
|
||||
MigrationName1736780194077,
|
||||
MigrationName1736780194078,
|
||||
MigrationName1736787495707,
|
||||
MigrationName1736787985322,
|
||||
MigrationName1736788706141,
|
||||
MigrationName1736856662868,
|
||||
MigrationName1737141420441,
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
RedisDb,
|
||||
RedisHostname,
|
||||
RedisIPFamily,
|
||||
RedisPassword,
|
||||
RedisPort,
|
||||
RedisTlsCa,
|
||||
@@ -40,6 +41,7 @@ export default abstract class Redis {
|
||||
password: RedisPassword,
|
||||
db: RedisDb,
|
||||
enableTLSForSentinelMode: RedisTlsSentinelMode,
|
||||
family: RedisIPFamily,
|
||||
lazyConnect: true,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Redis, { ClientType } from "./Redis";
|
||||
import { Mutex } from "redis-semaphore";
|
||||
import { Mutex, LockOptions } from "redis-semaphore";
|
||||
|
||||
export type SemaphoreMutex = Mutex;
|
||||
|
||||
@@ -8,7 +8,8 @@ export default class Semaphore {
|
||||
public static async lock(data: {
|
||||
key: string;
|
||||
namespace: string;
|
||||
lockTimeout?: number;
|
||||
lockTimeout?: number | undefined;
|
||||
acquireTimeout?: number | undefined;
|
||||
}): Promise<SemaphoreMutex> {
|
||||
if (!data.lockTimeout) {
|
||||
data.lockTimeout = 5000;
|
||||
@@ -22,12 +23,20 @@ export default class Semaphore {
|
||||
throw new Error("Redis client is not connected");
|
||||
}
|
||||
|
||||
const lockOptions: LockOptions = {};
|
||||
|
||||
if (data.lockTimeout) {
|
||||
lockOptions.lockTimeout = data.lockTimeout;
|
||||
}
|
||||
|
||||
if (data.acquireTimeout) {
|
||||
lockOptions.acquireTimeout = data.acquireTimeout;
|
||||
}
|
||||
|
||||
const mutex: SemaphoreMutex = new Mutex(
|
||||
client,
|
||||
data.namespace + "-" + key,
|
||||
{
|
||||
lockTimeout: data.lockTimeout,
|
||||
},
|
||||
lockOptions,
|
||||
);
|
||||
|
||||
await mutex.acquire();
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// This class checks the status of all the datasources.
|
||||
import Sleep from "../../Types/Sleep";
|
||||
import logger from "../Utils/Logger";
|
||||
import { ClickhouseAppInstance } from "./ClickhouseDatabase";
|
||||
import PostgresAppInstance from "./PostgresDatabase";
|
||||
import Redis from "./Redis";
|
||||
@@ -10,22 +12,58 @@ export default class InfrastructureStatus {
|
||||
checkPostgresStatus: boolean;
|
||||
checkClickhouseStatus: boolean;
|
||||
}): Promise<void> {
|
||||
logger.debug("Checking infrastructure status");
|
||||
|
||||
if (data.checkRedisStatus) {
|
||||
logger.debug("Checking Redis status");
|
||||
if (!(await Redis.checkConnnectionStatus())) {
|
||||
logger.debug("Redis is not connected");
|
||||
throw new DatabaseNotConnectedException("Redis is not connected");
|
||||
}
|
||||
logger.debug("Redis is connected");
|
||||
}
|
||||
|
||||
if (data.checkPostgresStatus) {
|
||||
logger.debug("Checking Postgres status");
|
||||
if (!(await PostgresAppInstance.checkConnnectionStatus())) {
|
||||
logger.debug("Postgres is not connected");
|
||||
throw new DatabaseNotConnectedException("Postgres is not connected");
|
||||
}
|
||||
logger.debug("Postgres is connected");
|
||||
}
|
||||
|
||||
if (data.checkClickhouseStatus) {
|
||||
logger.debug("Checking Clickhouse status");
|
||||
if (!(await ClickhouseAppInstance.checkConnnectionStatus())) {
|
||||
logger.debug("Clickhouse is not connected");
|
||||
throw new DatabaseNotConnectedException("Clickhouse is not connected");
|
||||
}
|
||||
logger.debug("Clickhouse is connected");
|
||||
}
|
||||
}
|
||||
|
||||
public static async checkStatusWithRetry(data: {
|
||||
retryCount: number;
|
||||
checkRedisStatus: boolean;
|
||||
checkPostgresStatus: boolean;
|
||||
checkClickhouseStatus: boolean;
|
||||
}): Promise<void> {
|
||||
let retry: number = 0;
|
||||
|
||||
while (retry < data.retryCount) {
|
||||
try {
|
||||
await this.checkStatus({
|
||||
checkRedisStatus: data.checkRedisStatus,
|
||||
checkPostgresStatus: data.checkPostgresStatus,
|
||||
checkClickhouseStatus: data.checkClickhouseStatus,
|
||||
});
|
||||
break;
|
||||
} catch (err) {
|
||||
logger.error("Error checking infrastructure status");
|
||||
logger.error(err);
|
||||
retry++;
|
||||
await Sleep.sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,31 +7,35 @@ import {
|
||||
import Response from "../Utils/Response";
|
||||
import Dictionary from "Common/Types/Dictionary";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
|
||||
export default class ClusterKeyAuthorization {
|
||||
public static getClusterKeyHeaders(): Dictionary<string> {
|
||||
return {
|
||||
clusterkey: ONEUPTIME_SECRET.toString(),
|
||||
clusterkey: ClusterKeyAuthorization.getClusterKey(),
|
||||
};
|
||||
}
|
||||
|
||||
public static getClusterKey(): string {
|
||||
// we encode uri component because a lot of people use special characters in their cluster key secret
|
||||
return encodeURIComponent(ONEUPTIME_SECRET.toString());
|
||||
}
|
||||
|
||||
public static async isAuthorizedServiceMiddleware(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
): Promise<void> {
|
||||
let clusterKey: ObjectID;
|
||||
let clusterKey: string;
|
||||
|
||||
if (req.params && req.params["clusterKey"]) {
|
||||
clusterKey = new ObjectID(req.params["clusterKey"]);
|
||||
clusterKey = req.params["clusterKey"];
|
||||
} else if (req.query && req.query["clusterKey"]) {
|
||||
clusterKey = new ObjectID(req.query["clusterKey"] as string);
|
||||
clusterKey = req.query["clusterKey"] as string;
|
||||
} else if (req.headers && req.headers["clusterkey"]) {
|
||||
// Header keys are automatically transformed to lowercase
|
||||
clusterKey = new ObjectID(req.headers["clusterkey"] as string);
|
||||
clusterKey = req.headers["clusterkey"] as string;
|
||||
} else if (req.body && req.body.clusterKey) {
|
||||
clusterKey = new ObjectID(req.body.clusterKey);
|
||||
clusterKey = req.body.clusterKey;
|
||||
} else {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
@@ -41,7 +45,7 @@ export default class ClusterKeyAuthorization {
|
||||
}
|
||||
|
||||
const isAuthorized: boolean =
|
||||
clusterKey.toString() === ONEUPTIME_SECRET.toString();
|
||||
clusterKey.toString() === ClusterKeyAuthorization.getClusterKey();
|
||||
|
||||
if (!isAuthorized) {
|
||||
return Response.sendErrorResponse(
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { ProbeExpressRequest } from "../Types/Request";
|
||||
import BadRequestException from "Common/Types/Exception/BadRequestException";
|
||||
import ProductType from "Common/Types/MeteredPlan/ProductType";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import BadRequestException from "../../Types/Exception/BadRequestException";
|
||||
import ProductType from "../../Types/MeteredPlan/ProductType";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
NextFunction,
|
||||
} from "Common/Server/Utils/Express";
|
||||
import TelemetryIngestionKeyService from "Common/Server/Services/TelemetryIngestionKeyService";
|
||||
import TelemetryIngestionKey from "Common/Models/DatabaseModels/TelemetryIngestionKey";
|
||||
} from "../../Server/Utils/Express";
|
||||
import TelemetryIngestionKeyService from "../../Server/Services/TelemetryIngestionKeyService";
|
||||
import TelemetryIngestionKey from "../../Models/DatabaseModels/TelemetryIngestionKey";
|
||||
|
||||
export interface TelemetryRequest extends ExpressRequest {
|
||||
projectId: ObjectID; // Project ID
|
||||
@@ -17,7 +16,7 @@ export interface TelemetryRequest extends ExpressRequest {
|
||||
|
||||
export default class TelemetryIngest {
|
||||
public static async isAuthorizedServiceMiddleware(
|
||||
req: ProbeExpressRequest,
|
||||
req: ExpressRequest,
|
||||
_res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
): Promise<void> {
|
||||
88
Common/Server/Services/AlertFeedService.ts
Normal file
88
Common/Server/Services/AlertFeedService.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { Blue500 } from "../../Types/BrandColors";
|
||||
import Color from "../../Types/Color";
|
||||
import OneUptimeDate from "../../Types/Date";
|
||||
import BadDataException from "../../Types/Exception/BadDataException";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import logger from "../Utils/Logger";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model, {
|
||||
AlertFeedEventType,
|
||||
} from "Common/Models/DatabaseModels/AlertFeed";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
|
||||
if (IsBillingEnabled) {
|
||||
this.hardDeleteItemsOlderThanInDays("createdAt", 120);
|
||||
}
|
||||
}
|
||||
|
||||
public async createAlertFeed(data: {
|
||||
alertId: ObjectID;
|
||||
feedInfoInMarkdown: string;
|
||||
alertFeedEventType: AlertFeedEventType;
|
||||
projectId: ObjectID;
|
||||
moreInformationInMarkdown?: string | undefined;
|
||||
displayColor?: Color | undefined;
|
||||
userId?: ObjectID | undefined;
|
||||
postedAt?: Date | undefined;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
if (!data.alertId) {
|
||||
throw new BadDataException("Alert ID is required");
|
||||
}
|
||||
|
||||
if (!data.feedInfoInMarkdown) {
|
||||
throw new BadDataException("Log in markdown is required");
|
||||
}
|
||||
|
||||
if (!data.alertFeedEventType) {
|
||||
throw new BadDataException("Alert log event is required");
|
||||
}
|
||||
|
||||
if (!data.projectId) {
|
||||
throw new BadDataException("Project ID is required");
|
||||
}
|
||||
|
||||
const alertFeed: Model = new Model();
|
||||
|
||||
if (!data.displayColor) {
|
||||
data.displayColor = Blue500;
|
||||
}
|
||||
|
||||
if (data.userId) {
|
||||
alertFeed.userId = data.userId;
|
||||
}
|
||||
|
||||
alertFeed.displayColor = data.displayColor;
|
||||
|
||||
alertFeed.alertId = data.alertId;
|
||||
alertFeed.feedInfoInMarkdown = data.feedInfoInMarkdown;
|
||||
alertFeed.alertFeedEventType = data.alertFeedEventType;
|
||||
alertFeed.projectId = data.projectId;
|
||||
|
||||
if (!data.postedAt) {
|
||||
alertFeed.postedAt = OneUptimeDate.getCurrentDate();
|
||||
}
|
||||
|
||||
if (data.moreInformationInMarkdown) {
|
||||
alertFeed.moreInformationInMarkdown = data.moreInformationInMarkdown;
|
||||
}
|
||||
|
||||
await this.create({
|
||||
data: alertFeed,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("AlertFeedService.createAlertFeed");
|
||||
logger.error(error);
|
||||
// we dont want to throw the error here, as this is a non-critical operation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
@@ -1,10 +1,83 @@
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/AlertInternalNote";
|
||||
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
import { Blue500 } from "../../Types/BrandColors";
|
||||
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
_onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
const userId: ObjectID | null | undefined =
|
||||
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: createdItem.alertId!,
|
||||
projectId: createdItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.PrivateNote,
|
||||
displayColor: Blue500,
|
||||
userId: userId || undefined,
|
||||
|
||||
feedInfoInMarkdown: `**Posted Internal / Private Note**
|
||||
|
||||
${createdItem.note}
|
||||
`,
|
||||
});
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
public override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
_updatedItemIds: Array<ObjectID>,
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (onUpdate.updateBy.data.note) {
|
||||
const updatedItems: Array<Model> = await this.findBy({
|
||||
query: onUpdate.updateBy.query,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
alertId: true,
|
||||
projectId: true,
|
||||
note: true,
|
||||
createdByUserId: true,
|
||||
createdByUser: {
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const userId: ObjectID | null | undefined =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
for (const updatedItem of updatedItems) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: updatedItem.alertId!,
|
||||
projectId: updatedItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.PrivateNote,
|
||||
displayColor: Blue500,
|
||||
userId: userId || undefined,
|
||||
|
||||
feedInfoInMarkdown: `**Updated Internal / Private Note**
|
||||
|
||||
${updatedItem.note}
|
||||
`,
|
||||
});
|
||||
}
|
||||
}
|
||||
return onUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -1,10 +1,122 @@
|
||||
import Team from "../../Models/DatabaseModels/Team";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import DeleteBy from "../Types/Database/DeleteBy";
|
||||
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/AlertOwnerTeam";
|
||||
import TeamService from "./TeamService";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
import { Gray500, Red500 } from "../../Types/BrandColors";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
deleteBy: DeleteBy<Model>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const itemsToDelete: Model[] = await this.findBy({
|
||||
query: deleteBy.query,
|
||||
limit: deleteBy.limit,
|
||||
skip: deleteBy.skip,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
alertId: true,
|
||||
projectId: true,
|
||||
teamId: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
carryForward: {
|
||||
itemsToDelete: itemsToDelete,
|
||||
},
|
||||
deleteBy: deleteBy,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onDeleteSuccess(
|
||||
onDelete: OnDelete<Model>,
|
||||
_itemIdsBeforeDelete: Array<ObjectID>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const deleteByUserId: ObjectID | undefined =
|
||||
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
||||
|
||||
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
||||
|
||||
for (const item of itemsToDelete) {
|
||||
const alertId: ObjectID | undefined = item.alertId;
|
||||
const projectId: ObjectID | undefined = item.projectId;
|
||||
const teamId: ObjectID | undefined = item.teamId;
|
||||
|
||||
if (alertId && teamId && projectId) {
|
||||
const team: Team | null = await TeamService.findOneById({
|
||||
id: teamId,
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (team && team.name) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: projectId,
|
||||
alertFeedEventType: AlertFeedEventType.OwnerTeamRemoved,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Team ${team.name}** was removed from the alert as the owner.`,
|
||||
userId: deleteByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onDelete;
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
// add alert feed.
|
||||
|
||||
const alertId: ObjectID | undefined = createdItem.alertId;
|
||||
const projectId: ObjectID | undefined = createdItem.projectId;
|
||||
const teamId: ObjectID | undefined = createdItem.teamId;
|
||||
const createdByUserId: ObjectID | undefined =
|
||||
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
||||
|
||||
if (alertId && teamId && projectId) {
|
||||
const team: Team | null = await TeamService.findOneById({
|
||||
id: teamId,
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (team && team.name) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: projectId,
|
||||
alertFeedEventType: AlertFeedEventType.OwnerTeamAdded,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Team ${team.name}** was added to the alert as the owner.`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -1,10 +1,124 @@
|
||||
import User from "../../Models/DatabaseModels/User";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import DeleteBy from "../Types/Database/DeleteBy";
|
||||
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/AlertOwnerUser";
|
||||
import UserService from "./UserService";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
import { Gray500, Red500 } from "../../Types/BrandColors";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
deleteBy: DeleteBy<Model>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const itemsToDelete: Model[] = await this.findBy({
|
||||
query: deleteBy.query,
|
||||
limit: deleteBy.limit,
|
||||
skip: deleteBy.skip,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
alertId: true,
|
||||
projectId: true,
|
||||
userId: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
carryForward: {
|
||||
itemsToDelete: itemsToDelete,
|
||||
},
|
||||
deleteBy: deleteBy,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onDeleteSuccess(
|
||||
onDelete: OnDelete<Model>,
|
||||
_itemIdsBeforeDelete: Array<ObjectID>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const deleteByUserId: ObjectID | undefined =
|
||||
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
||||
|
||||
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
||||
|
||||
for (const item of itemsToDelete) {
|
||||
const alertId: ObjectID | undefined = item.alertId;
|
||||
const projectId: ObjectID | undefined = item.projectId;
|
||||
const userId: ObjectID | undefined = item.userId;
|
||||
|
||||
if (alertId && userId && projectId) {
|
||||
const user: User | null = await UserService.findOneById({
|
||||
id: userId,
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user && user.name) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: projectId,
|
||||
alertFeedEventType: AlertFeedEventType.OwnerUserRemoved,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**${user.name.toString()}** (${user.email?.toString()}) was removed from the alert as the owner.`,
|
||||
userId: deleteByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onDelete;
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
// add alert feed.
|
||||
|
||||
const alertId: ObjectID | undefined = createdItem.alertId;
|
||||
const projectId: ObjectID | undefined = createdItem.projectId;
|
||||
const userId: ObjectID | undefined = createdItem.userId;
|
||||
const createdByUserId: ObjectID | undefined =
|
||||
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
||||
|
||||
if (alertId && userId && projectId) {
|
||||
const user: User | null = await UserService.findOneById({
|
||||
id: userId,
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user && user.name) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: projectId,
|
||||
alertFeedEventType: AlertFeedEventType.OwnerUserAdded,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**${user.name.toString()}** (${user.email?.toString()}) was added to the alert as the owner.`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -28,6 +28,19 @@ import AlertState from "Common/Models/DatabaseModels/AlertState";
|
||||
import AlertStateTimeline from "Common/Models/DatabaseModels/AlertStateTimeline";
|
||||
import User from "Common/Models/DatabaseModels/User";
|
||||
import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import TelemetryType from "../../Types/Telemetry/TelemetryType";
|
||||
import logger from "../Utils/Logger";
|
||||
import TelemetryUtil from "../Utils/Telemetry/Telemetry";
|
||||
import MetricService from "./MetricService";
|
||||
import OneUptimeDate from "../../Types/Date";
|
||||
import Metric, {
|
||||
MetricPointType,
|
||||
ServiceType,
|
||||
} from "../../Models/AnalyticsModels/Metric";
|
||||
import AlertMetricType from "../../Types/Alerts/AlertMetricType";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
import { Gray500, Red500 } from "../../Types/BrandColors";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
@@ -214,6 +227,48 @@ export class Service extends DatabaseService<Model> {
|
||||
throw new BadDataException("currentAlertStateId is required");
|
||||
}
|
||||
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: createdItem.id!,
|
||||
projectId: createdItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.AlertCreated,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Alert Created**:
|
||||
|
||||
**Alert Title**:
|
||||
|
||||
${createdItem.title || "No title provided."}
|
||||
|
||||
**Description**:
|
||||
|
||||
${createdItem.description || "No description provided."}
|
||||
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: createdItem.id!,
|
||||
projectId: createdItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.RootCause,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Root Cause**
|
||||
|
||||
${createdItem.rootCause || "No root cause provided."}`,
|
||||
});
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: createdItem.id!,
|
||||
projectId: createdItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.RemediationNotes,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Remediation Notes**
|
||||
|
||||
${createdItem.remediationNotes || "No remediation notes provided."}`,
|
||||
});
|
||||
|
||||
await this.changeAlertState({
|
||||
projectId: createdItem.projectId,
|
||||
alertId: createdItem.id,
|
||||
@@ -435,6 +490,82 @@ export class Service extends DatabaseService<Model> {
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedItemIds.length > 0) {
|
||||
for (const alertId of updatedItemIds) {
|
||||
if (onUpdate.updateBy.data.title) {
|
||||
// add alert feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Alert title was updated.** Here's the new title.
|
||||
|
||||
${onUpdate.updateBy.data.title || "No title provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (onUpdate.updateBy.data.rootCause) {
|
||||
// add alert feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Alert root cause was updated.** Here's the new root cause.
|
||||
|
||||
${onUpdate.updateBy.data.rootCause || "No root cause provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (onUpdate.updateBy.data.description) {
|
||||
// add alert feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Alert description was updated.** Here's the new description.
|
||||
|
||||
${onUpdate.updateBy.data.description || "No description provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (onUpdate.updateBy.data.remediationNotes) {
|
||||
// add alert feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: alertId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Remediation notes were updated.** Here are the new notes.
|
||||
|
||||
${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
|
||||
@@ -564,5 +695,265 @@ export class Service extends DatabaseService<Model> {
|
||||
props: props || {},
|
||||
});
|
||||
}
|
||||
|
||||
public async refreshAlertMetrics(data: { alertId: ObjectID }): Promise<void> {
|
||||
const alert: Model | null = await this.findOneById({
|
||||
id: data.alertId,
|
||||
select: {
|
||||
projectId: true,
|
||||
monitor: {
|
||||
_id: true,
|
||||
name: true,
|
||||
},
|
||||
alertSeverity: {
|
||||
name: true,
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!alert) {
|
||||
throw new BadDataException("Alert not found");
|
||||
}
|
||||
|
||||
if (!alert.projectId) {
|
||||
throw new BadDataException("Incient Project ID not found");
|
||||
}
|
||||
|
||||
// get alert state timeline
|
||||
|
||||
const alertStateTimelines: Array<AlertStateTimeline> =
|
||||
await AlertStateTimelineService.findBy({
|
||||
query: {
|
||||
alertId: data.alertId,
|
||||
},
|
||||
select: {
|
||||
projectId: true,
|
||||
alertStateId: true,
|
||||
alertState: {
|
||||
isAcknowledgedState: true,
|
||||
isResolvedState: true,
|
||||
},
|
||||
startsAt: true,
|
||||
endsAt: true,
|
||||
},
|
||||
sort: {
|
||||
startsAt: SortOrder.Ascending,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
const firstAlertStateTimeline: AlertStateTimeline | undefined =
|
||||
alertStateTimelines[0];
|
||||
|
||||
// delete all the alert metrics with this alert id because its a refresh.
|
||||
|
||||
await MetricService.deleteBy({
|
||||
query: {
|
||||
serviceId: data.alertId,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
const itemsToSave: Array<Metric> = [];
|
||||
|
||||
// now we need to create new metrics for this alert - TimeToAcknowledge, TimeToResolve, AlertCount, AlertDuration
|
||||
|
||||
const alertStartsAt: Date =
|
||||
firstAlertStateTimeline?.startsAt ||
|
||||
alert.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
|
||||
const alertCountMetric: Metric = new Metric();
|
||||
|
||||
alertCountMetric.projectId = alert.projectId;
|
||||
alertCountMetric.serviceId = alert.id!;
|
||||
alertCountMetric.serviceType = ServiceType.Alert;
|
||||
alertCountMetric.name = AlertMetricType.AlertCount;
|
||||
alertCountMetric.description = "Number of alerts created";
|
||||
alertCountMetric.value = 1;
|
||||
alertCountMetric.unit = "";
|
||||
alertCountMetric.attributes = {
|
||||
alertId: data.alertId.toString(),
|
||||
projectId: alert.projectId.toString(),
|
||||
monitorId: alert.monitor?.id!.toString() || "",
|
||||
monitorName: alert.monitor?.name!.toString() || "",
|
||||
alertSeverityId: alert.alertSeverity?.id!.toString() || "",
|
||||
alertSeverityName: alert.alertSeverity?.name!.toString() || "",
|
||||
};
|
||||
|
||||
alertCountMetric.time = alertStartsAt;
|
||||
alertCountMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
alertCountMetric.time,
|
||||
);
|
||||
alertCountMetric.metricPointType = MetricPointType.Sum;
|
||||
|
||||
itemsToSave.push(alertCountMetric);
|
||||
|
||||
// is the alert acknowledged?
|
||||
const isAlertAcknowledged: boolean = alertStateTimelines.some(
|
||||
(timeline: AlertStateTimeline) => {
|
||||
return timeline.alertState?.isAcknowledgedState;
|
||||
},
|
||||
);
|
||||
|
||||
if (isAlertAcknowledged) {
|
||||
const ackAlertStateTimeline: AlertStateTimeline | undefined =
|
||||
alertStateTimelines.find((timeline: AlertStateTimeline) => {
|
||||
return timeline.alertState?.isAcknowledgedState;
|
||||
});
|
||||
|
||||
if (ackAlertStateTimeline) {
|
||||
const timeToAcknowledgeMetric: Metric = new Metric();
|
||||
|
||||
timeToAcknowledgeMetric.projectId = alert.projectId;
|
||||
timeToAcknowledgeMetric.serviceId = alert.id!;
|
||||
timeToAcknowledgeMetric.serviceType = ServiceType.Alert;
|
||||
timeToAcknowledgeMetric.name = AlertMetricType.TimeToAcknowledge;
|
||||
timeToAcknowledgeMetric.description =
|
||||
"Time taken to acknowledge the alert";
|
||||
timeToAcknowledgeMetric.value = OneUptimeDate.getDifferenceInSeconds(
|
||||
ackAlertStateTimeline?.startsAt || OneUptimeDate.getCurrentDate(),
|
||||
alertStartsAt,
|
||||
);
|
||||
timeToAcknowledgeMetric.unit = "seconds";
|
||||
timeToAcknowledgeMetric.attributes = {
|
||||
alertId: data.alertId.toString(),
|
||||
projectId: alert.projectId.toString(),
|
||||
monitorId: alert.monitor?.id!.toString() || "",
|
||||
monitorName: alert.monitor?.name!.toString() || "",
|
||||
alertSeverityId: alert.alertSeverity?.id!.toString() || "",
|
||||
alertSeverityName: alert.alertSeverity?.name!.toString() || "",
|
||||
};
|
||||
|
||||
timeToAcknowledgeMetric.time =
|
||||
ackAlertStateTimeline?.startsAt ||
|
||||
alert.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
timeToAcknowledgeMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
timeToAcknowledgeMetric.time,
|
||||
);
|
||||
timeToAcknowledgeMetric.metricPointType = MetricPointType.Sum;
|
||||
|
||||
itemsToSave.push(timeToAcknowledgeMetric);
|
||||
}
|
||||
}
|
||||
|
||||
// time to resolve
|
||||
const isAlertResolved: boolean = alertStateTimelines.some(
|
||||
(timeline: AlertStateTimeline) => {
|
||||
return timeline.alertState?.isResolvedState;
|
||||
},
|
||||
);
|
||||
|
||||
if (isAlertResolved) {
|
||||
const resolvedAlertStateTimeline: AlertStateTimeline | undefined =
|
||||
alertStateTimelines.find((timeline: AlertStateTimeline) => {
|
||||
return timeline.alertState?.isResolvedState;
|
||||
});
|
||||
|
||||
if (resolvedAlertStateTimeline) {
|
||||
const timeToResolveMetric: Metric = new Metric();
|
||||
|
||||
timeToResolveMetric.projectId = alert.projectId;
|
||||
timeToResolveMetric.serviceId = alert.id!;
|
||||
timeToResolveMetric.serviceType = ServiceType.Alert;
|
||||
timeToResolveMetric.name = AlertMetricType.TimeToResolve;
|
||||
timeToResolveMetric.description = "Time taken to resolve the alert";
|
||||
timeToResolveMetric.value = OneUptimeDate.getDifferenceInSeconds(
|
||||
resolvedAlertStateTimeline?.startsAt ||
|
||||
OneUptimeDate.getCurrentDate(),
|
||||
alertStartsAt,
|
||||
);
|
||||
timeToResolveMetric.unit = "seconds";
|
||||
timeToResolveMetric.attributes = {
|
||||
alertId: data.alertId.toString(),
|
||||
projectId: alert.projectId.toString(),
|
||||
monitorId: alert.monitor?.id!.toString() || "",
|
||||
monitorName: alert.monitor?.name!.toString() || "",
|
||||
alertSeverityId: alert.alertSeverity?.id!.toString() || "",
|
||||
alertSeverityName: alert.alertSeverity?.name!.toString() || "",
|
||||
};
|
||||
|
||||
timeToResolveMetric.time =
|
||||
resolvedAlertStateTimeline?.startsAt ||
|
||||
alert.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
timeToResolveMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
timeToResolveMetric.time,
|
||||
);
|
||||
timeToResolveMetric.metricPointType = MetricPointType.Sum;
|
||||
|
||||
itemsToSave.push(timeToResolveMetric);
|
||||
}
|
||||
}
|
||||
|
||||
// alert duration
|
||||
|
||||
const alertDurationMetric: Metric = new Metric();
|
||||
|
||||
const lastAlertStateTimeline: AlertStateTimeline | undefined =
|
||||
alertStateTimelines[alertStateTimelines.length - 1];
|
||||
|
||||
if (lastAlertStateTimeline) {
|
||||
const alertEndsAt: Date =
|
||||
lastAlertStateTimeline.startsAt || OneUptimeDate.getCurrentDate();
|
||||
|
||||
// save metric.
|
||||
|
||||
alertDurationMetric.projectId = alert.projectId;
|
||||
alertDurationMetric.serviceId = alert.id!;
|
||||
alertDurationMetric.serviceType = ServiceType.Alert;
|
||||
alertDurationMetric.name = AlertMetricType.AlertDuration;
|
||||
alertDurationMetric.description = "Duration of the alert";
|
||||
alertDurationMetric.value = OneUptimeDate.getDifferenceInSeconds(
|
||||
alertEndsAt,
|
||||
alertStartsAt,
|
||||
);
|
||||
alertDurationMetric.unit = "seconds";
|
||||
alertDurationMetric.attributes = {
|
||||
alertId: data.alertId.toString(),
|
||||
projectId: alert.projectId.toString(),
|
||||
monitorId: alert.monitor?.id!.toString() || "",
|
||||
monitorName: alert.monitor?.name!.toString() || "",
|
||||
alertSeverityId: alert.alertSeverity?.id!.toString() || "",
|
||||
alertSeverityName: alert.alertSeverity?.name!.toString() || "",
|
||||
};
|
||||
|
||||
alertDurationMetric.time =
|
||||
lastAlertStateTimeline?.startsAt ||
|
||||
alert.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
alertDurationMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
alertDurationMetric.time,
|
||||
);
|
||||
alertDurationMetric.metricPointType = MetricPointType.Sum;
|
||||
}
|
||||
|
||||
await MetricService.createMany({
|
||||
items: itemsToSave,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
// index attributes.
|
||||
TelemetryUtil.indexAttributes({
|
||||
attributes: ["monitorId", "projectId", "alertId", "monitorNames"],
|
||||
projectId: alert.projectId,
|
||||
telemetryType: TelemetryType.Metric,
|
||||
}).catch((err: Error) => {
|
||||
logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
|
||||
@@ -18,6 +18,9 @@ import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import { JSONObject } from "../../Types/JSON";
|
||||
import AlertInternalNote from "../../Models/DatabaseModels/AlertInternalNote";
|
||||
import AlertInternalNoteService from "./AlertInternalNoteService";
|
||||
import logger from "../Utils/Logger";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
|
||||
export class Service extends DatabaseService<AlertStateTimeline> {
|
||||
public constructor() {
|
||||
@@ -129,10 +132,15 @@ export class Service extends DatabaseService<AlertStateTimeline> {
|
||||
});
|
||||
}
|
||||
|
||||
const privateNote: string | undefined = (
|
||||
createBy.miscDataProps as JSONObject | undefined
|
||||
)?.["privateNote"] as string | undefined;
|
||||
|
||||
return {
|
||||
createBy,
|
||||
carryForward: {
|
||||
lastAlertStateTimelineId: lastAlertStateTimeline?.id || null,
|
||||
privateNote: privateNote,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -163,6 +171,36 @@ export class Service extends DatabaseService<AlertStateTimeline> {
|
||||
});
|
||||
}
|
||||
|
||||
const alertState: AlertState | null = await AlertStateService.findOneBy({
|
||||
query: {
|
||||
_id: createdItem.alertStateId.toString()!,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
isResolvedState: true,
|
||||
isAcknowledgedState: true,
|
||||
isCreatedState: true,
|
||||
color: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
|
||||
const stateName: string = alertState?.name || "";
|
||||
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: createdItem.alertId!,
|
||||
projectId: createdItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.AlertStateChanged,
|
||||
displayColor: alertState?.color,
|
||||
feedInfoInMarkdown: "**Alert State** changed to **" + stateName + "**",
|
||||
moreInformationInMarkdown: `**Cause:**
|
||||
${createdItem.rootCause}`,
|
||||
userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
|
||||
});
|
||||
|
||||
await AlertService.updateOneBy({
|
||||
query: {
|
||||
_id: createdItem.alertId?.toString(),
|
||||
@@ -173,6 +211,30 @@ export class Service extends DatabaseService<AlertStateTimeline> {
|
||||
props: onCreate.createBy.props,
|
||||
});
|
||||
|
||||
if (onCreate.carryForward.privateNote) {
|
||||
const privateNote: string = onCreate.carryForward.privateNote;
|
||||
|
||||
const alertInternalNote: AlertInternalNote = new AlertInternalNote();
|
||||
alertInternalNote.alertId = createdItem.alertId;
|
||||
alertInternalNote.note = privateNote;
|
||||
alertInternalNote.createdAt = createdItem.startsAt!;
|
||||
alertInternalNote.projectId = createdItem.projectId!;
|
||||
|
||||
await AlertInternalNoteService.create({
|
||||
data: alertInternalNote,
|
||||
props: onCreate.createBy.props,
|
||||
});
|
||||
}
|
||||
|
||||
AlertService.refreshAlertMetrics({
|
||||
alertId: createdItem.alertId,
|
||||
}).catch((error: Error) => {
|
||||
logger.error(
|
||||
"Error while refreshing alert metrics after alert state timeline creation",
|
||||
);
|
||||
logger.error(error);
|
||||
});
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -259,6 +259,11 @@ export default class AnalyticsDatabaseService<
|
||||
|
||||
// convert date column from string to date.
|
||||
|
||||
const groupByColumnName: keyof TBaseModel | undefined =
|
||||
aggregateBy.groupBy && Object.keys(aggregateBy.groupBy).length > 0
|
||||
? (Object.keys(aggregateBy.groupBy)[0] as keyof TBaseModel)
|
||||
: undefined;
|
||||
|
||||
for (const item of items) {
|
||||
if (
|
||||
!(item as JSONObject)[
|
||||
@@ -268,6 +273,21 @@ export default class AnalyticsDatabaseService<
|
||||
continue;
|
||||
}
|
||||
|
||||
// if value is of type string then convert it to number.
|
||||
|
||||
if (
|
||||
typeof (item as JSONObject)[
|
||||
aggregateBy.aggregateColumnName as string
|
||||
] === Typeof.String
|
||||
) {
|
||||
(item as JSONObject)[aggregateBy.aggregateColumnName as string] =
|
||||
Number.parseFloat(
|
||||
(item as JSONObject)[
|
||||
aggregateBy.aggregateColumnName as string
|
||||
] as string,
|
||||
);
|
||||
}
|
||||
|
||||
const aggregatedModel: AggregatedModel = {
|
||||
timestamp: OneUptimeDate.fromString(
|
||||
(item as JSONObject)[
|
||||
@@ -277,6 +297,9 @@ export default class AnalyticsDatabaseService<
|
||||
value: (item as JSONObject)[
|
||||
aggregateBy.aggregateColumnName as string
|
||||
] as number,
|
||||
[groupByColumnName as string]: (item as JSONObject)[
|
||||
groupByColumnName as string
|
||||
],
|
||||
};
|
||||
|
||||
aggregatedItems.push(aggregatedModel);
|
||||
@@ -360,6 +383,9 @@ export default class AnalyticsDatabaseService<
|
||||
findStatement.statement,
|
||||
);
|
||||
|
||||
logger.debug(`${this.model.tableName} Find Statement executed`);
|
||||
logger.debug(findStatement.statement);
|
||||
|
||||
const strResult: string = await StreamUtil.convertStreamToText(
|
||||
dbResult.stream,
|
||||
);
|
||||
@@ -389,6 +415,10 @@ export default class AnalyticsDatabaseService<
|
||||
strResult: string,
|
||||
columns: string[],
|
||||
): JSONObject[] {
|
||||
if (!strResult || !strResult.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const jsonItems: Array<JSONObject> = [];
|
||||
|
||||
const rows: Array<string> = strResult.split("\n");
|
||||
@@ -457,7 +487,7 @@ export default class AnalyticsDatabaseService<
|
||||
count()
|
||||
FROM ${databaseName}.${this.model.tableName}
|
||||
WHERE TRUE `.append(whereStatement);
|
||||
|
||||
|
||||
|
||||
if (countBy.groupBy && Object.keys(countBy.groupBy).length > 0) {
|
||||
statement.append(
|
||||
@@ -519,9 +549,11 @@ export default class AnalyticsDatabaseService<
|
||||
statement.append(SQL` FROM ${databaseName}.${this.model.tableName}`);
|
||||
statement.append(SQL` WHERE TRUE `).append(whereStatement);
|
||||
|
||||
|
||||
statement.append(SQL` GROUP BY `).append(`${aggregateBy.aggregationTimestampColumnName.toString()}`);
|
||||
|
||||
statement.append(SQL` GROUP BY `).append(`${aggregateBy.aggregationTimestampColumnName.toString()}`);
|
||||
|
||||
if (aggregateBy.groupBy && Object.keys(aggregateBy.groupBy).length > 0) {
|
||||
statement.append(SQL` , `).append(this.statementGenerator.toGroupByStatement(aggregateBy.groupBy));
|
||||
}
|
||||
|
||||
statement.append(SQL` ORDER BY `).append(sortStatement);
|
||||
|
||||
@@ -538,7 +570,7 @@ export default class AnalyticsDatabaseService<
|
||||
}}
|
||||
`);
|
||||
|
||||
|
||||
|
||||
|
||||
logger.debug(`${this.model.tableName} Aggregate Statement`);
|
||||
logger.debug(statement);
|
||||
@@ -604,7 +636,7 @@ export default class AnalyticsDatabaseService<
|
||||
}}
|
||||
`);
|
||||
|
||||
|
||||
|
||||
|
||||
logger.debug(`${this.model.tableName} Find Statement`);
|
||||
logger.debug(statement);
|
||||
@@ -626,7 +658,7 @@ export default class AnalyticsDatabaseService<
|
||||
const statement: Statement = SQL`
|
||||
ALTER TABLE ${databaseName}.${this.model.tableName}
|
||||
DELETE WHERE TRUE `.append(whereStatement);
|
||||
|
||||
|
||||
|
||||
logger.debug(`${this.model.tableName} Delete Statement`);
|
||||
logger.debug(statement);
|
||||
@@ -676,7 +708,13 @@ export default class AnalyticsDatabaseService<
|
||||
(select as any)[tenantColumnName] = true;
|
||||
}
|
||||
|
||||
await this.execute(this.toDeleteStatement(beforeDeleteBy));
|
||||
const deleteStatement: Statement = this.toDeleteStatement(beforeDeleteBy);
|
||||
|
||||
await this.execute(deleteStatement);
|
||||
|
||||
logger.debug(`${this.model.tableName} Delete Statement executed`);
|
||||
logger.debug(deleteStatement);
|
||||
|
||||
} catch (error) {
|
||||
await this.onDeleteError(error as Exception);
|
||||
throw this.getException(error as Exception);
|
||||
@@ -727,9 +765,17 @@ export default class AnalyticsDatabaseService<
|
||||
(select as any)[tenantColumnName] = true;
|
||||
}
|
||||
|
||||
await this.execute(
|
||||
this.statementGenerator.toUpdateStatement(beforeUpdateBy),
|
||||
const statement: Statement = this.statementGenerator.toUpdateStatement(
|
||||
beforeUpdateBy,
|
||||
);
|
||||
|
||||
await this.execute(
|
||||
statement,
|
||||
);
|
||||
|
||||
logger.debug(`${this.model.tableName} Update Statement executed`);
|
||||
logger.debug(statement);
|
||||
|
||||
} catch (error) {
|
||||
await this.onUpdateError(error as Exception);
|
||||
throw this.getException(error as Exception);
|
||||
@@ -766,7 +812,7 @@ export default class AnalyticsDatabaseService<
|
||||
: {
|
||||
query: statement, // TODO remove and only accept Statements
|
||||
},
|
||||
);
|
||||
) as ExecResult<Stream>;
|
||||
}
|
||||
|
||||
protected async onUpdateSuccess(
|
||||
@@ -914,6 +960,10 @@ export default class AnalyticsDatabaseService<
|
||||
|
||||
await this.execute(insertStatement);
|
||||
|
||||
|
||||
logger.debug(`${this.model.tableName} Create Statement executed`);
|
||||
logger.debug(insertStatement);
|
||||
|
||||
if (!createBy.props.ignoreHooks) {
|
||||
for (let i: number = 0; i < items.length; i++) {
|
||||
if (!items[i]) {
|
||||
|
||||
@@ -10,6 +10,11 @@ import Model, {
|
||||
InvoiceStatus,
|
||||
} from "Common/Models/DatabaseModels/BillingInvoice";
|
||||
import Project from "Common/Models/DatabaseModels/Project";
|
||||
import SubscriptionStatus from "../../Types/Billing/SubscriptionStatus";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
|
||||
import logger from "../Utils/Logger";
|
||||
import OneUptimeDate from "../../Types/Date";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
@@ -17,6 +22,166 @@ export class Service extends DatabaseService<Model> {
|
||||
this.setDoNotAllowDelete(true);
|
||||
}
|
||||
|
||||
public async refreshSubscriptionStatus(data: {
|
||||
projectId: ObjectID;
|
||||
}): Promise<void> {
|
||||
let mutex: SemaphoreMutex | null = null;
|
||||
|
||||
try {
|
||||
mutex = await Semaphore.lock({
|
||||
key: data.projectId.toString(),
|
||||
namespace: "BillingInoviceService.refreshSubscriptionStatus",
|
||||
lockTimeout: 15000,
|
||||
acquireTimeout: 20000,
|
||||
});
|
||||
logger.debug(
|
||||
"Mutex acquired - " +
|
||||
data.projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
"Mutex acquire failed - " +
|
||||
data.projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
let project: Project | null = await ProjectService.findOneById({
|
||||
id: data.projectId,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
paymentProviderCustomerId: true,
|
||||
paymentProviderSubscriptionId: true,
|
||||
paymentProviderMeteredSubscriptionId: true,
|
||||
},
|
||||
});
|
||||
|
||||
// refresh the subscription status. This is a hack to ensure that the subscription status is always up to date.
|
||||
// This is because the subscription status can change at any time and we need to ensure that the subscription status is always up to date.
|
||||
|
||||
if (!project) {
|
||||
throw new BadDataException("Project not found");
|
||||
}
|
||||
|
||||
if (!project.paymentProviderCustomerId) {
|
||||
throw new BadDataException("Payment provider customer id not found.");
|
||||
}
|
||||
|
||||
let subscriptionState: SubscriptionStatus =
|
||||
await BillingService.getSubscriptionStatus(
|
||||
project.paymentProviderSubscriptionId as string,
|
||||
);
|
||||
|
||||
let meteredSubscriptionState: SubscriptionStatus =
|
||||
await BillingService.getSubscriptionStatus(
|
||||
project.paymentProviderMeteredSubscriptionId as string,
|
||||
);
|
||||
|
||||
// update the project.
|
||||
|
||||
await ProjectService.updateOneById({
|
||||
id: project.id!,
|
||||
data: {
|
||||
paymentProviderSubscriptionStatus: subscriptionState,
|
||||
paymentProviderMeteredSubscriptionStatus: meteredSubscriptionState,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
ignoreHooks: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
meteredSubscriptionState === SubscriptionStatus.Canceled ||
|
||||
subscriptionState === SubscriptionStatus.Canceled
|
||||
) {
|
||||
// check if all invoices are paid. If yes, then reactivate the subscription.
|
||||
|
||||
const invoices: Array<Invoice> = await BillingService.getInvoices(
|
||||
project.paymentProviderCustomerId,
|
||||
);
|
||||
|
||||
let allInvoicesPaid: boolean = true;
|
||||
|
||||
for (const invoice of invoices) {
|
||||
if (
|
||||
invoice.status === InvoiceStatus.Open ||
|
||||
invoice.status === InvoiceStatus.Uncollectible
|
||||
) {
|
||||
allInvoicesPaid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allInvoicesPaid) {
|
||||
await ProjectService.reactiveSubscription(project.id!);
|
||||
project = await ProjectService.findOneById({
|
||||
id: data.projectId,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
paymentProviderCustomerId: true,
|
||||
paymentProviderSubscriptionId: true,
|
||||
paymentProviderMeteredSubscriptionId: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
throw new BadDataException("Project not found");
|
||||
}
|
||||
|
||||
subscriptionState = await BillingService.getSubscriptionStatus(
|
||||
project.paymentProviderSubscriptionId as string,
|
||||
);
|
||||
|
||||
meteredSubscriptionState = await BillingService.getSubscriptionStatus(
|
||||
project.paymentProviderMeteredSubscriptionId as string,
|
||||
);
|
||||
|
||||
await ProjectService.updateOneById({
|
||||
id: project.id!,
|
||||
data: {
|
||||
paymentProviderSubscriptionStatus: subscriptionState,
|
||||
paymentProviderMeteredSubscriptionStatus: meteredSubscriptionState,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
ignoreHooks: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (mutex) {
|
||||
try {
|
||||
await Semaphore.release(mutex);
|
||||
logger.debug(
|
||||
"Mutex released - " +
|
||||
data.projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
"Mutex release failed - " +
|
||||
data.projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
logger.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async onBeforeFind(
|
||||
findBy: FindBy<Model>,
|
||||
): Promise<OnFind<Model>> {
|
||||
@@ -37,6 +202,11 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
// refresh the subscription status. This is a hack to ensure that the subscription status is always up to date.
|
||||
// This is because the subscription status can change at any time and we need to ensure that the subscription status is always up to date.
|
||||
|
||||
await this.refreshSubscriptionStatus({ projectId: findBy.props.tenantId! });
|
||||
|
||||
if (!project) {
|
||||
throw new BadDataException("Project not found");
|
||||
}
|
||||
|
||||
@@ -437,10 +437,10 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
||||
const columns: Columns = this.model.getTableColumns();
|
||||
|
||||
for (const columnName of columns.columns) {
|
||||
if (this.model.isEntityColumn(columnName)) {
|
||||
const tableColumnMetadata: TableColumnMetadata =
|
||||
this.model.getTableColumnMetadata(columnName);
|
||||
const tableColumnMetadata: TableColumnMetadata =
|
||||
this.model.getTableColumnMetadata(columnName);
|
||||
|
||||
if (this.model.isEntityColumn(columnName)) {
|
||||
const columnValue: JSONValue = (data as any)[columnName];
|
||||
|
||||
if (
|
||||
@@ -507,6 +507,14 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
||||
(data as any)[columnName] = columnValue.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// if its a Date column and if date is null then set it to null.
|
||||
if (
|
||||
(data as any)[columnName] === "" &&
|
||||
tableColumnMetadata.type === TableColumnType.Date
|
||||
) {
|
||||
(data as any)[columnName] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// check createByUserId.
|
||||
@@ -1384,6 +1392,9 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
||||
...data,
|
||||
} as any;
|
||||
|
||||
logger.debug("Updated Item");
|
||||
logger.debug(JSON.stringify(updatedItem, null, 2));
|
||||
|
||||
await this.getRepository().save(updatedItem);
|
||||
|
||||
// hit workflow.
|
||||
|
||||
94
Common/Server/Services/IncidentFeedService.ts
Normal file
94
Common/Server/Services/IncidentFeedService.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Blue500 } from "../../Types/BrandColors";
|
||||
import Color from "../../Types/Color";
|
||||
import OneUptimeDate from "../../Types/Date";
|
||||
import BadDataException from "../../Types/Exception/BadDataException";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import logger from "../Utils/Logger";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import IncidentFeed, {
|
||||
IncidentFeedEventType,
|
||||
} from "Common/Models/DatabaseModels/IncidentFeed";
|
||||
|
||||
export class Service extends DatabaseService<IncidentFeed> {
|
||||
public constructor() {
|
||||
super(IncidentFeed);
|
||||
|
||||
if (IsBillingEnabled) {
|
||||
this.hardDeleteItemsOlderThanInDays("createdAt", 120);
|
||||
}
|
||||
}
|
||||
|
||||
public async createIncidentFeed(data: {
|
||||
incidentId: ObjectID;
|
||||
feedInfoInMarkdown: string;
|
||||
incidentFeedEventType: IncidentFeedEventType;
|
||||
projectId: ObjectID;
|
||||
moreInformationInMarkdown?: string | undefined;
|
||||
displayColor?: Color | undefined;
|
||||
userId?: ObjectID | undefined;
|
||||
postedAt?: Date | undefined;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
logger.debug("IncidentFeedService.createIncidentFeed");
|
||||
logger.debug(data);
|
||||
|
||||
const incidentFeed: IncidentFeed = new IncidentFeed();
|
||||
|
||||
if (!data.incidentId) {
|
||||
throw new BadDataException("Incident ID is required");
|
||||
}
|
||||
|
||||
if (!data.feedInfoInMarkdown) {
|
||||
throw new BadDataException("Log in markdown is required");
|
||||
}
|
||||
|
||||
if (!data.incidentFeedEventType) {
|
||||
throw new BadDataException("Incident log event is required");
|
||||
}
|
||||
|
||||
if (!data.projectId) {
|
||||
throw new BadDataException("Project ID is required");
|
||||
}
|
||||
|
||||
if (!data.displayColor) {
|
||||
data.displayColor = Blue500;
|
||||
}
|
||||
|
||||
incidentFeed.displayColor = data.displayColor;
|
||||
incidentFeed.incidentId = data.incidentId;
|
||||
incidentFeed.feedInfoInMarkdown = data.feedInfoInMarkdown;
|
||||
incidentFeed.incidentFeedEventType = data.incidentFeedEventType;
|
||||
incidentFeed.projectId = data.projectId;
|
||||
|
||||
if (!data.postedAt) {
|
||||
incidentFeed.postedAt = OneUptimeDate.getCurrentDate();
|
||||
}
|
||||
|
||||
if (data.userId) {
|
||||
incidentFeed.userId = data.userId;
|
||||
}
|
||||
|
||||
if (data.moreInformationInMarkdown) {
|
||||
incidentFeed.moreInformationInMarkdown = data.moreInformationInMarkdown;
|
||||
}
|
||||
|
||||
const createdIncidentFeed: IncidentFeed = await this.create({
|
||||
data: incidentFeed,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug("Incident Feed created");
|
||||
logger.debug(createdIncidentFeed);
|
||||
} catch (e) {
|
||||
logger.error("Error in creating incident feed");
|
||||
logger.error(e);
|
||||
|
||||
// we dont throw this error as it is not a critical error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
@@ -1,10 +1,83 @@
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/IncidentInternalNote";
|
||||
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import { Blue500 } from "../../Types/BrandColors";
|
||||
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
_onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
const userId: ObjectID | null | undefined =
|
||||
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.incidentId!,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.PrivateNote,
|
||||
displayColor: Blue500,
|
||||
userId: userId || undefined,
|
||||
|
||||
feedInfoInMarkdown: `**Posted Internal / Private Note**
|
||||
|
||||
${createdItem.note}
|
||||
`,
|
||||
});
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
public override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
_updatedItemIds: Array<ObjectID>,
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (onUpdate.updateBy.data.note) {
|
||||
const updatedItems: Array<Model> = await this.findBy({
|
||||
query: onUpdate.updateBy.query,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
incidentId: true,
|
||||
projectId: true,
|
||||
note: true,
|
||||
createdByUserId: true,
|
||||
createdByUser: {
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const userId: ObjectID | null | undefined =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
for (const updatedItem of updatedItems) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: updatedItem.incidentId!,
|
||||
projectId: updatedItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.PrivateNote,
|
||||
displayColor: Blue500,
|
||||
userId: userId || undefined,
|
||||
|
||||
feedInfoInMarkdown: `**Updated Internal / Private Note**
|
||||
|
||||
${updatedItem.note}
|
||||
`,
|
||||
});
|
||||
}
|
||||
}
|
||||
return onUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -1,10 +1,122 @@
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/IncidentOwnerTeam";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import { Gray500, Red500 } from "../../Types/BrandColors";
|
||||
import TeamService from "./TeamService";
|
||||
import Team from "../../Models/DatabaseModels/Team";
|
||||
import DeleteBy from "../Types/Database/DeleteBy";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
deleteBy: DeleteBy<Model>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const itemsToDelete: Model[] = await this.findBy({
|
||||
query: deleteBy.query,
|
||||
limit: deleteBy.limit,
|
||||
skip: deleteBy.skip,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
incidentId: true,
|
||||
projectId: true,
|
||||
teamId: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
carryForward: {
|
||||
itemsToDelete: itemsToDelete,
|
||||
},
|
||||
deleteBy: deleteBy,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onDeleteSuccess(
|
||||
onDelete: OnDelete<Model>,
|
||||
_itemIdsBeforeDelete: Array<ObjectID>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const deleteByUserId: ObjectID | undefined =
|
||||
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
||||
|
||||
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
||||
|
||||
for (const item of itemsToDelete) {
|
||||
const incidentId: ObjectID | undefined = item.incidentId;
|
||||
const projectId: ObjectID | undefined = item.projectId;
|
||||
const teamId: ObjectID | undefined = item.teamId;
|
||||
|
||||
if (incidentId && teamId && projectId) {
|
||||
const team: Team | null = await TeamService.findOneById({
|
||||
id: teamId,
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (team && team.name) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: projectId,
|
||||
incidentFeedEventType: IncidentFeedEventType.OwnerTeamRemoved,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Team ${team.name}** was removed from the incident as the owner.`,
|
||||
userId: deleteByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onDelete;
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
// add incident feed.
|
||||
|
||||
const incidentId: ObjectID | undefined = createdItem.incidentId;
|
||||
const projectId: ObjectID | undefined = createdItem.projectId;
|
||||
const teamId: ObjectID | undefined = createdItem.teamId;
|
||||
const createdByUserId: ObjectID | undefined =
|
||||
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
||||
|
||||
if (incidentId && teamId && projectId) {
|
||||
const team: Team | null = await TeamService.findOneById({
|
||||
id: teamId,
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (team && team.name) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: projectId,
|
||||
incidentFeedEventType: IncidentFeedEventType.OwnerTeamAdded,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Team ${team.name}** was added to the incident as the owner.`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -1,10 +1,124 @@
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/IncidentOwnerUser";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import { Gray500, Red500 } from "../../Types/BrandColors";
|
||||
import User from "../../Models/DatabaseModels/User";
|
||||
import UserService from "./UserService";
|
||||
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
||||
import DeleteBy from "../Types/Database/DeleteBy";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
deleteBy: DeleteBy<Model>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const itemsToDelete: Model[] = await this.findBy({
|
||||
query: deleteBy.query,
|
||||
limit: deleteBy.limit,
|
||||
skip: deleteBy.skip,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
incidentId: true,
|
||||
projectId: true,
|
||||
userId: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
carryForward: {
|
||||
itemsToDelete: itemsToDelete,
|
||||
},
|
||||
deleteBy: deleteBy,
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onDeleteSuccess(
|
||||
onDelete: OnDelete<Model>,
|
||||
_itemIdsBeforeDelete: Array<ObjectID>,
|
||||
): Promise<OnDelete<Model>> {
|
||||
const deleteByUserId: ObjectID | undefined =
|
||||
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
||||
|
||||
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
||||
|
||||
for (const item of itemsToDelete) {
|
||||
const incidentId: ObjectID | undefined = item.incidentId;
|
||||
const projectId: ObjectID | undefined = item.projectId;
|
||||
const userId: ObjectID | undefined = item.userId;
|
||||
|
||||
if (incidentId && userId && projectId) {
|
||||
const user: User | null = await UserService.findOneById({
|
||||
id: userId,
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user && user.name) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: projectId,
|
||||
incidentFeedEventType: IncidentFeedEventType.OwnerUserRemoved,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**${user.name.toString()}** (${user.email?.toString()}) was removed from the incident as the owner.`,
|
||||
userId: deleteByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onDelete;
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
// add incident feed.
|
||||
|
||||
const incidentId: ObjectID | undefined = createdItem.incidentId;
|
||||
const projectId: ObjectID | undefined = createdItem.projectId;
|
||||
const userId: ObjectID | undefined = createdItem.userId;
|
||||
const createdByUserId: ObjectID | undefined =
|
||||
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
||||
|
||||
if (incidentId && userId && projectId) {
|
||||
const user: User | null = await UserService.findOneById({
|
||||
id: userId,
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (user && user.name) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: projectId,
|
||||
incidentFeedEventType: IncidentFeedEventType.OwnerUserAdded,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**${user.name.toString()}** (${user.email?.toString()}) was added to the incident as the owner.`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import CreateBy from "../Types/Database/CreateBy";
|
||||
import { OnCreate } from "../Types/Database/Hooks";
|
||||
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import OneUptimeDate from "../../Types/Date";
|
||||
import Model from "Common/Models/DatabaseModels/IncidentPublicNote";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import { Blue500, Indigo500 } from "../../Types/BrandColors";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
@@ -21,6 +26,72 @@ export class Service extends DatabaseService<Model> {
|
||||
carryForward: null,
|
||||
};
|
||||
}
|
||||
|
||||
public override async onCreateSuccess(
|
||||
_onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
const userId: ObjectID | null | undefined =
|
||||
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.incidentId!,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.PublicNote,
|
||||
displayColor: Indigo500,
|
||||
userId: userId || undefined,
|
||||
feedInfoInMarkdown: `**Posted public note for this incident on status page**
|
||||
|
||||
${createdItem.note}
|
||||
`,
|
||||
});
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
public override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
_updatedItemIds: Array<ObjectID>,
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (onUpdate.updateBy.data.note) {
|
||||
const updatedItems: Array<Model> = await this.findBy({
|
||||
query: onUpdate.updateBy.query,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
incidentId: true,
|
||||
projectId: true,
|
||||
note: true,
|
||||
createdByUserId: true,
|
||||
createdByUser: {
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const userId: ObjectID | null | undefined =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
for (const updatedItem of updatedItems) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: updatedItem.incidentId!,
|
||||
projectId: updatedItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.PublicNote,
|
||||
displayColor: Blue500,
|
||||
userId: userId || undefined,
|
||||
|
||||
feedInfoInMarkdown: `**Updated Public Note**
|
||||
|
||||
${updatedItem.note}
|
||||
`,
|
||||
});
|
||||
}
|
||||
}
|
||||
return onUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
|
||||
@@ -34,6 +34,22 @@ import MonitorStatus from "Common/Models/DatabaseModels/MonitorStatus";
|
||||
import MonitorStatusTimeline from "Common/Models/DatabaseModels/MonitorStatusTimeline";
|
||||
import User from "Common/Models/DatabaseModels/User";
|
||||
import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import MetricService from "./MetricService";
|
||||
import IncidentMetricType from "../../Types/Incident/IncidentMetricType";
|
||||
import Metric, {
|
||||
MetricPointType,
|
||||
ServiceType,
|
||||
} from "../../Models/AnalyticsModels/Metric";
|
||||
import OneUptimeDate from "../../Types/Date";
|
||||
import TelemetryUtil from "../Utils/Telemetry/Telemetry";
|
||||
import TelemetryType from "../../Types/Telemetry/TelemetryType";
|
||||
import logger from "../Utils/Logger";
|
||||
import Semaphore, {
|
||||
SemaphoreMutex,
|
||||
} from "Common/Server/Infrastructure/Semaphore";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import { Gray500, Red500 } from "../../Types/BrandColors";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
@@ -139,6 +155,34 @@ export class Service extends DatabaseService<Model> {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
// store incident metric
|
||||
}
|
||||
|
||||
public async getExistingIncidentNumberForProject(data: {
|
||||
projectId: ObjectID;
|
||||
}): Promise<number> {
|
||||
// get last incident number.
|
||||
const lastIncident: Model | null = await this.findOneBy({
|
||||
query: {
|
||||
projectId: data.projectId,
|
||||
},
|
||||
select: {
|
||||
incidentNumber: true,
|
||||
},
|
||||
sort: {
|
||||
createdAt: SortOrder.Descending,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!lastIncident) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return lastIncident.incidentNumber || 0;
|
||||
}
|
||||
|
||||
protected override async onBeforeCreate(
|
||||
@@ -148,10 +192,13 @@ export class Service extends DatabaseService<Model> {
|
||||
throw new BadDataException("ProjectId required to create incident.");
|
||||
}
|
||||
|
||||
const projectId: ObjectID =
|
||||
createBy.props.tenantId || createBy.data.projectId!;
|
||||
|
||||
const incidentState: IncidentState | null =
|
||||
await IncidentStateService.findOneBy({
|
||||
query: {
|
||||
projectId: createBy.props.tenantId || createBy.data.projectId!,
|
||||
projectId: projectId,
|
||||
isCreatedState: true,
|
||||
},
|
||||
select: {
|
||||
@@ -168,7 +215,39 @@ export class Service extends DatabaseService<Model> {
|
||||
);
|
||||
}
|
||||
|
||||
let mutex: SemaphoreMutex | null = null;
|
||||
|
||||
try {
|
||||
mutex = await Semaphore.lock({
|
||||
key: projectId.toString(),
|
||||
namespace: "IncidentService.incident-create",
|
||||
lockTimeout: 15000,
|
||||
acquireTimeout: 20000,
|
||||
});
|
||||
|
||||
logger.debug(
|
||||
"Mutex acquired - IncidentService.incident-create " +
|
||||
projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
"Mutex acquire failed - IncidentService.incident-create " +
|
||||
projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
const incidentNumberForThisIncident: number =
|
||||
(await this.getExistingIncidentNumberForProject({
|
||||
projectId: projectId,
|
||||
})) + 1;
|
||||
|
||||
createBy.data.currentIncidentStateId = incidentState.id;
|
||||
createBy.data.incidentNumber = incidentNumberForThisIncident;
|
||||
|
||||
if (
|
||||
(createBy.data.createdByUserId ||
|
||||
@@ -205,13 +284,19 @@ export class Service extends DatabaseService<Model> {
|
||||
}
|
||||
}
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
return {
|
||||
createBy,
|
||||
carryForward: {
|
||||
mutex: mutex,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
// these should never be null.
|
||||
if (!createdItem.projectId) {
|
||||
throw new BadDataException("projectId is required");
|
||||
}
|
||||
@@ -220,6 +305,52 @@ export class Service extends DatabaseService<Model> {
|
||||
throw new BadDataException("id is required");
|
||||
}
|
||||
|
||||
// release the mutex.
|
||||
if (onCreate.carryForward && onCreate.carryForward.mutex) {
|
||||
const mutex: SemaphoreMutex = onCreate.carryForward.mutex;
|
||||
const projectId: ObjectID = createdItem.projectId!;
|
||||
|
||||
try {
|
||||
await Semaphore.release(mutex);
|
||||
logger.debug(
|
||||
"Mutex released - IncidentService.incident-create " +
|
||||
projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
"Mutex release failed - IncidentService.incident-create " +
|
||||
projectId.toString() +
|
||||
" at " +
|
||||
OneUptimeDate.getCurrentDateAsFormattedString(),
|
||||
);
|
||||
logger.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.id!,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.IncidentCreated,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Incident #${createdItem.incidentNumber?.toString()} Created**:
|
||||
|
||||
**Incident Title**:
|
||||
|
||||
${createdItem.title || "No title provided."}
|
||||
|
||||
**Description**:
|
||||
|
||||
${createdItem.description || "No description provided."}
|
||||
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
|
||||
if (!createdItem.currentIncidentStateId) {
|
||||
throw new BadDataException("currentIncidentStateId is required");
|
||||
}
|
||||
@@ -260,6 +391,26 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.id!,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.RootCause,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Root Cause**
|
||||
|
||||
${createdItem.rootCause || "No root cause provided."}`,
|
||||
});
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.id!,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.RemediationNotes,
|
||||
displayColor: Red500,
|
||||
feedInfoInMarkdown: `**Remediation Notes**
|
||||
|
||||
${createdItem.remediationNotes || "No remediation notes provided."}`,
|
||||
});
|
||||
|
||||
// add owners.
|
||||
|
||||
if (
|
||||
@@ -491,6 +642,82 @@ export class Service extends DatabaseService<Model> {
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedItemIds.length > 0) {
|
||||
for (const incidentId of updatedItemIds) {
|
||||
if (onUpdate.updateBy.data.title) {
|
||||
// add incident feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Incident title was updated.** Here's the new title.
|
||||
|
||||
${onUpdate.updateBy.data.title || "No title provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (onUpdate.updateBy.data.rootCause) {
|
||||
// add incident feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Incident root cause was updated.** Here's the new root cause.
|
||||
|
||||
${onUpdate.updateBy.data.rootCause || "No root cause provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (onUpdate.updateBy.data.description) {
|
||||
// add incident feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Incident description was updated.** Here's the new description.
|
||||
|
||||
${onUpdate.updateBy.data.description || "No description provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (onUpdate.updateBy.data.remediationNotes) {
|
||||
// add incident feed.
|
||||
const createdByUserId: ObjectID | undefined | null =
|
||||
onUpdate.updateBy.props.userId;
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: incidentId,
|
||||
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
||||
incidentFeedEventType: IncidentFeedEventType.IncidentUpdated,
|
||||
displayColor: Gray500,
|
||||
feedInfoInMarkdown: `**Remediation notes were updated.** Here are the new notes.
|
||||
|
||||
${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
|
||||
`,
|
||||
userId: createdByUserId || undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
|
||||
@@ -737,5 +964,291 @@ export class Service extends DatabaseService<Model> {
|
||||
props: props || {},
|
||||
});
|
||||
}
|
||||
|
||||
public async refreshIncidentMetrics(data: {
|
||||
incidentId: ObjectID;
|
||||
}): Promise<void> {
|
||||
const incident: Model | null = await this.findOneById({
|
||||
id: data.incidentId,
|
||||
select: {
|
||||
projectId: true,
|
||||
monitors: {
|
||||
_id: true,
|
||||
name: true,
|
||||
},
|
||||
incidentSeverity: {
|
||||
_id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!incident) {
|
||||
throw new BadDataException("Incident not found");
|
||||
}
|
||||
|
||||
if (!incident.projectId) {
|
||||
throw new BadDataException("Incient Project ID not found");
|
||||
}
|
||||
|
||||
// get incident state timeline
|
||||
|
||||
const incidentStateTimelines: Array<IncidentStateTimeline> =
|
||||
await IncidentStateTimelineService.findBy({
|
||||
query: {
|
||||
incidentId: data.incidentId,
|
||||
},
|
||||
select: {
|
||||
projectId: true,
|
||||
incidentStateId: true,
|
||||
incidentState: {
|
||||
isAcknowledgedState: true,
|
||||
isResolvedState: true,
|
||||
},
|
||||
startsAt: true,
|
||||
endsAt: true,
|
||||
},
|
||||
sort: {
|
||||
startsAt: SortOrder.Ascending,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
const firstIncidentStateTimeline: IncidentStateTimeline | undefined =
|
||||
incidentStateTimelines[0];
|
||||
|
||||
// delete all the incident metrics with this incident id because its a refresh.
|
||||
|
||||
await MetricService.deleteBy({
|
||||
query: {
|
||||
serviceId: data.incidentId,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
const itemsToSave: Array<Metric> = [];
|
||||
|
||||
// now we need to create new metrics for this incident - TimeToAcknowledge, TimeToResolve, IncidentCount, IncidentDuration
|
||||
|
||||
const incidentStartsAt: Date =
|
||||
firstIncidentStateTimeline?.startsAt ||
|
||||
incident.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
|
||||
const incidentCountMetric: Metric = new Metric();
|
||||
|
||||
incidentCountMetric.projectId = incident.projectId;
|
||||
incidentCountMetric.serviceId = incident.id!;
|
||||
incidentCountMetric.serviceType = ServiceType.Incident;
|
||||
incidentCountMetric.name = IncidentMetricType.IncidentCount;
|
||||
incidentCountMetric.description = "Number of incidents created";
|
||||
incidentCountMetric.value = 1;
|
||||
incidentCountMetric.unit = "";
|
||||
incidentCountMetric.attributes = {
|
||||
incidentId: data.incidentId.toString(),
|
||||
projectId: incident.projectId.toString(),
|
||||
monitorIds:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor._id?.toString();
|
||||
}) || [],
|
||||
monitorNames:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor.name?.toString();
|
||||
}) || [],
|
||||
incidentSeverityId: incident.incidentSeverity?._id?.toString(),
|
||||
incidentSeverityName: incident.incidentSeverity?.name?.toString(),
|
||||
};
|
||||
|
||||
incidentCountMetric.time = incidentStartsAt;
|
||||
incidentCountMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
incidentCountMetric.time,
|
||||
);
|
||||
incidentCountMetric.metricPointType = MetricPointType.Sum;
|
||||
|
||||
itemsToSave.push(incidentCountMetric);
|
||||
|
||||
// is the incident acknowledged?
|
||||
const isIncidentAcknowledged: boolean = incidentStateTimelines.some(
|
||||
(timeline: IncidentStateTimeline) => {
|
||||
return timeline.incidentState?.isAcknowledgedState;
|
||||
},
|
||||
);
|
||||
|
||||
if (isIncidentAcknowledged) {
|
||||
const ackIncidentStateTimeline: IncidentStateTimeline | undefined =
|
||||
incidentStateTimelines.find((timeline: IncidentStateTimeline) => {
|
||||
return timeline.incidentState?.isAcknowledgedState;
|
||||
});
|
||||
|
||||
if (ackIncidentStateTimeline) {
|
||||
const timeToAcknowledgeMetric: Metric = new Metric();
|
||||
|
||||
timeToAcknowledgeMetric.projectId = incident.projectId;
|
||||
timeToAcknowledgeMetric.serviceId = incident.id!;
|
||||
timeToAcknowledgeMetric.serviceType = ServiceType.Incident;
|
||||
timeToAcknowledgeMetric.name = IncidentMetricType.TimeToAcknowledge;
|
||||
timeToAcknowledgeMetric.description =
|
||||
"Time taken to acknowledge the incident";
|
||||
timeToAcknowledgeMetric.value = OneUptimeDate.getDifferenceInSeconds(
|
||||
ackIncidentStateTimeline?.startsAt || OneUptimeDate.getCurrentDate(),
|
||||
incidentStartsAt,
|
||||
);
|
||||
timeToAcknowledgeMetric.unit = "seconds";
|
||||
timeToAcknowledgeMetric.attributes = {
|
||||
incidentId: data.incidentId.toString(),
|
||||
projectId: incident.projectId.toString(),
|
||||
monitorIds:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor._id?.toString();
|
||||
}) || [],
|
||||
monitorNames:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor.name?.toString();
|
||||
}) || [],
|
||||
incidentSeverityId: incident.incidentSeverity?._id?.toString(),
|
||||
incidentSeverityName: incident.incidentSeverity?.name?.toString(),
|
||||
};
|
||||
|
||||
timeToAcknowledgeMetric.time =
|
||||
ackIncidentStateTimeline?.startsAt ||
|
||||
incident.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
timeToAcknowledgeMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
timeToAcknowledgeMetric.time,
|
||||
);
|
||||
timeToAcknowledgeMetric.metricPointType = MetricPointType.Sum;
|
||||
|
||||
itemsToSave.push(timeToAcknowledgeMetric);
|
||||
}
|
||||
}
|
||||
|
||||
// time to resolve
|
||||
const isIncidentResolved: boolean = incidentStateTimelines.some(
|
||||
(timeline: IncidentStateTimeline) => {
|
||||
return timeline.incidentState?.isResolvedState;
|
||||
},
|
||||
);
|
||||
|
||||
if (isIncidentResolved) {
|
||||
const resolvedIncidentStateTimeline: IncidentStateTimeline | undefined =
|
||||
incidentStateTimelines.find((timeline: IncidentStateTimeline) => {
|
||||
return timeline.incidentState?.isResolvedState;
|
||||
});
|
||||
|
||||
if (resolvedIncidentStateTimeline) {
|
||||
const timeToResolveMetric: Metric = new Metric();
|
||||
|
||||
timeToResolveMetric.projectId = incident.projectId;
|
||||
timeToResolveMetric.serviceId = incident.id!;
|
||||
timeToResolveMetric.serviceType = ServiceType.Incident;
|
||||
timeToResolveMetric.name = IncidentMetricType.TimeToResolve;
|
||||
timeToResolveMetric.description = "Time taken to resolve the incident";
|
||||
timeToResolveMetric.value = OneUptimeDate.getDifferenceInSeconds(
|
||||
resolvedIncidentStateTimeline?.startsAt ||
|
||||
OneUptimeDate.getCurrentDate(),
|
||||
incidentStartsAt,
|
||||
);
|
||||
timeToResolveMetric.unit = "seconds";
|
||||
timeToResolveMetric.attributes = {
|
||||
incidentId: data.incidentId.toString(),
|
||||
projectId: incident.projectId.toString(),
|
||||
monitorIds:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor._id?.toString();
|
||||
}) || [],
|
||||
monitorNames:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor.name?.toString();
|
||||
}) || [],
|
||||
incidentSeverityId: incident.incidentSeverity?._id?.toString(),
|
||||
incidentSeverityName: incident.incidentSeverity?.name?.toString(),
|
||||
};
|
||||
|
||||
timeToResolveMetric.time =
|
||||
resolvedIncidentStateTimeline?.startsAt ||
|
||||
incident.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
timeToResolveMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
timeToResolveMetric.time,
|
||||
);
|
||||
timeToResolveMetric.metricPointType = MetricPointType.Sum;
|
||||
|
||||
itemsToSave.push(timeToResolveMetric);
|
||||
}
|
||||
}
|
||||
|
||||
// incident duration
|
||||
|
||||
const incidentDurationMetric: Metric = new Metric();
|
||||
|
||||
const lastIncidentStateTimeline: IncidentStateTimeline | undefined =
|
||||
incidentStateTimelines[incidentStateTimelines.length - 1];
|
||||
|
||||
if (lastIncidentStateTimeline) {
|
||||
const incidentEndsAt: Date =
|
||||
lastIncidentStateTimeline.startsAt || OneUptimeDate.getCurrentDate();
|
||||
|
||||
// save metric.
|
||||
|
||||
incidentDurationMetric.projectId = incident.projectId;
|
||||
incidentDurationMetric.serviceId = incident.id!;
|
||||
incidentDurationMetric.serviceType = ServiceType.Incident;
|
||||
incidentDurationMetric.name = IncidentMetricType.IncidentDuration;
|
||||
incidentDurationMetric.description = "Duration of the incident";
|
||||
incidentDurationMetric.value = OneUptimeDate.getDifferenceInSeconds(
|
||||
incidentEndsAt,
|
||||
incidentStartsAt,
|
||||
);
|
||||
incidentDurationMetric.unit = "seconds";
|
||||
incidentDurationMetric.attributes = {
|
||||
incidentId: data.incidentId.toString(),
|
||||
projectId: incident.projectId.toString(),
|
||||
monitorIds:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor._id?.toString();
|
||||
}) || [],
|
||||
monitorNames:
|
||||
incident.monitors?.map((monitor: Monitor) => {
|
||||
return monitor.name?.toString();
|
||||
}) || [],
|
||||
incidentSeverityId: incident.incidentSeverity?._id?.toString(),
|
||||
incidentSeverityName: incident.incidentSeverity?.name?.toString(),
|
||||
};
|
||||
|
||||
incidentDurationMetric.time =
|
||||
lastIncidentStateTimeline?.startsAt ||
|
||||
incident.createdAt ||
|
||||
OneUptimeDate.getCurrentDate();
|
||||
incidentDurationMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
||||
incidentDurationMetric.time,
|
||||
);
|
||||
incidentDurationMetric.metricPointType = MetricPointType.Sum;
|
||||
}
|
||||
|
||||
await MetricService.createMany({
|
||||
items: itemsToSave,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
// index attributes.
|
||||
TelemetryUtil.indexAttributes({
|
||||
attributes: ["monitorIds", "projectId", "incidentId", "monitorNames"],
|
||||
projectId: incident.projectId,
|
||||
telemetryType: TelemetryType.Metric,
|
||||
}).catch((err: Error) => {
|
||||
logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
|
||||
@@ -19,6 +19,9 @@ import IncidentState from "Common/Models/DatabaseModels/IncidentState";
|
||||
import IncidentStateTimeline from "Common/Models/DatabaseModels/IncidentStateTimeline";
|
||||
import User from "Common/Models/DatabaseModels/User";
|
||||
import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import logger from "../Utils/Logger";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
|
||||
export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
public constructor() {
|
||||
@@ -119,32 +122,17 @@ export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
)?.["publicNote"] as string | undefined;
|
||||
|
||||
if (publicNote) {
|
||||
const incidentPublicNote: IncidentPublicNote = new IncidentPublicNote();
|
||||
incidentPublicNote.incidentId = createBy.data.incidentId;
|
||||
incidentPublicNote.note = publicNote;
|
||||
incidentPublicNote.postedAt = createBy.data.startsAt;
|
||||
incidentPublicNote.createdAt = createBy.data.startsAt;
|
||||
incidentPublicNote.projectId = createBy.data.projectId!;
|
||||
incidentPublicNote.shouldStatusPageSubscribersBeNotifiedOnNoteCreated =
|
||||
Boolean(createBy.data.shouldStatusPageSubscribersBeNotified);
|
||||
|
||||
// mark status page subscribers as notified for this state change because we dont want to send duplicate (two) emails one for public note and one for state change.
|
||||
if (
|
||||
incidentPublicNote.shouldStatusPageSubscribersBeNotifiedOnNoteCreated
|
||||
) {
|
||||
if (createBy.data.shouldStatusPageSubscribersBeNotified) {
|
||||
createBy.data.isStatusPageSubscribersNotified = true;
|
||||
}
|
||||
|
||||
await IncidentPublicNoteService.create({
|
||||
data: incidentPublicNote,
|
||||
props: createBy.props,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
createBy,
|
||||
carryForward: {
|
||||
lastIncidentStateTimelineId: lastIncidentStateTimeline?.id || null,
|
||||
publicNote: publicNote,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -188,20 +176,39 @@ export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
// TODO: DELETE THIS WHEN WORKFLOW IS IMPLEMENMTED.
|
||||
// check if this is resolved state, and if it is then resolve all the monitors.
|
||||
|
||||
const isResolvedState: IncidentState | null =
|
||||
const incidentState: IncidentState | null =
|
||||
await IncidentStateService.findOneBy({
|
||||
query: {
|
||||
_id: createdItem.incidentStateId.toString()!,
|
||||
isResolvedState: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
isResolvedState: true,
|
||||
isAcknowledgedState: true,
|
||||
isCreatedState: true,
|
||||
color: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
|
||||
const stateName: string = incidentState?.name || "";
|
||||
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.incidentId!,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.IncidentStateChanged,
|
||||
displayColor: incidentState?.color,
|
||||
feedInfoInMarkdown: "**Incident State** changed to **" + stateName + "**",
|
||||
moreInformationInMarkdown: `**Cause:**
|
||||
${createdItem.rootCause}`,
|
||||
userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
|
||||
});
|
||||
|
||||
const isResolvedState: boolean = incidentState?.isResolvedState || false;
|
||||
|
||||
if (isResolvedState) {
|
||||
const incident: Incident | null = await IncidentService.findOneBy({
|
||||
query: {
|
||||
@@ -227,6 +234,31 @@ export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
}
|
||||
}
|
||||
|
||||
if (onCreate.carryForward.publicNote) {
|
||||
const publicNote: string = onCreate.carryForward.publicNote;
|
||||
|
||||
const incidentPublicNote: IncidentPublicNote = new IncidentPublicNote();
|
||||
incidentPublicNote.incidentId = createdItem.incidentId;
|
||||
incidentPublicNote.note = publicNote;
|
||||
incidentPublicNote.postedAt = createdItem.startsAt!;
|
||||
incidentPublicNote.createdAt = createdItem.startsAt!;
|
||||
incidentPublicNote.projectId = createdItem.projectId!;
|
||||
incidentPublicNote.shouldStatusPageSubscribersBeNotifiedOnNoteCreated =
|
||||
Boolean(createdItem.shouldStatusPageSubscribersBeNotified);
|
||||
|
||||
await IncidentPublicNoteService.create({
|
||||
data: incidentPublicNote,
|
||||
props: onCreate.createBy.props,
|
||||
});
|
||||
}
|
||||
|
||||
IncidentService.refreshIncidentMetrics({
|
||||
incidentId: createdItem.incidentId,
|
||||
}).catch((error: Error) => {
|
||||
logger.error(`Error while refreshing incident metrics:`);
|
||||
logger.error(error);
|
||||
});
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import MonitorGroupOwnerTeamService from "./MonitorGroupOwnerTeamService";
|
||||
import MonitorGroupOwnerUserService from "./MonitorGroupOwnerUserService";
|
||||
import MonitorGroupResourceService from "./MonitorGroupResourceService";
|
||||
import MonitorGroupService from "./MonitorGroupService";
|
||||
import MonitorMetricsByMinuteService from "./MonitorMetricsByMinuteService";
|
||||
import MonitorOwnerTeamService from "./MonitorOwnerTeamService";
|
||||
import MonitorOwnerUserService from "./MonitorOwnerUserService";
|
||||
import MonitorProbeService from "./MonitorProbeService";
|
||||
@@ -148,6 +147,9 @@ import AlertOwnerUserService from "./AlertOwnerUserService";
|
||||
import AlertSeverityService from "./AlertSeverityService";
|
||||
import AlertNoteTemplateService from "./AlertNoteTemplateService";
|
||||
import TableViewService from "./TableViewService";
|
||||
import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
|
||||
const services: Array<BaseService> = [
|
||||
AcmeCertificateService,
|
||||
@@ -187,6 +189,7 @@ const services: Array<BaseService> = [
|
||||
IncidentSeverityService,
|
||||
IncidentStateService,
|
||||
IncidentStateTimelineService,
|
||||
IncidentFeedService,
|
||||
|
||||
LabelService,
|
||||
|
||||
@@ -223,6 +226,7 @@ const services: Array<BaseService> = [
|
||||
ScheduledMaintenanceService,
|
||||
ScheduledMaintenanceStateService,
|
||||
ScheduledMaintenanceStateTimelineService,
|
||||
ScheduledMaintenanceFeedService,
|
||||
|
||||
ShortLinkService,
|
||||
SmsLogService,
|
||||
@@ -307,6 +311,8 @@ const services: Array<BaseService> = [
|
||||
AlertOwnerUserService,
|
||||
AlertSeverityService,
|
||||
AlertNoteTemplateService,
|
||||
AlertFeedService,
|
||||
|
||||
TableViewService,
|
||||
];
|
||||
|
||||
@@ -316,7 +322,6 @@ export const AnalyticsServices: Array<
|
||||
LogService,
|
||||
SpanService,
|
||||
MetricService,
|
||||
MonitorMetricsByMinuteService,
|
||||
TelemetryAttributeService,
|
||||
ExceptionInstanceService,
|
||||
];
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import ClickhouseDatabase from "../Infrastructure/ClickhouseDatabase";
|
||||
import AnalyticsDatabaseService from "./AnalyticsDatabaseService";
|
||||
import MonitorMetricsByMinute from "Common/Models/AnalyticsModels/MonitorMetricsByMinute";
|
||||
|
||||
export class MonitorMetricsByMinuteService extends AnalyticsDatabaseService<MonitorMetricsByMinute> {
|
||||
public constructor(clickhouseDatabase?: ClickhouseDatabase | undefined) {
|
||||
super({
|
||||
modelType: MonitorMetricsByMinute,
|
||||
database: clickhouseDatabase,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new MonitorMetricsByMinuteService();
|
||||
@@ -97,6 +97,11 @@ export class Service extends DatabaseService<MonitorStatusTimeline> {
|
||||
},
|
||||
});
|
||||
|
||||
if (!lastMonitorStatusTimeline) {
|
||||
// since this is the first status, do not notify the owner.
|
||||
createBy.data.isOwnerNotified = true;
|
||||
}
|
||||
|
||||
return {
|
||||
createBy,
|
||||
carryForward: {
|
||||
|
||||
@@ -30,6 +30,7 @@ import OnCallDutyPolicyEscalationRuleTeam from "Common/Models/DatabaseModels/OnC
|
||||
import OnCallDutyPolicyEscalationRuleUser from "Common/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser";
|
||||
import OnCallDutyPolicyExecutionLogTimeline from "Common/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline";
|
||||
import User from "Common/Models/DatabaseModels/User";
|
||||
import logger from "../Utils/Logger";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public async startRuleExecution(
|
||||
@@ -37,12 +38,13 @@ export class Service extends DatabaseService<Model> {
|
||||
options: {
|
||||
projectId: ObjectID;
|
||||
triggeredByIncidentId?: ObjectID | undefined;
|
||||
triggeredByAlertId?: ObjectID | undefined;
|
||||
userNotificationEventType: UserNotificationEventType;
|
||||
onCallPolicyExecutionLogId: ObjectID;
|
||||
onCallPolicyId: ObjectID;
|
||||
},
|
||||
): Promise<void> {
|
||||
// add log timeline.
|
||||
logger.debug(`Starting rule execution for ruleId: ${ruleId.toString()}`);
|
||||
|
||||
const rule: Model | null = await this.findOneById({
|
||||
id: ruleId,
|
||||
@@ -62,6 +64,8 @@ export class Service extends DatabaseService<Model> {
|
||||
);
|
||||
}
|
||||
|
||||
logger.debug(`Found rule: ${JSON.stringify(rule)}`);
|
||||
|
||||
await OnCallDutyPolicyExecutionLogService.updateOneById({
|
||||
id: options.onCallPolicyExecutionLogId,
|
||||
data: {
|
||||
@@ -75,6 +79,8 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Updated execution log for ruleId: ${ruleId.toString()}`);
|
||||
|
||||
type GetNewLogFunction = () => OnCallDutyPolicyExecutionLogTimeline;
|
||||
|
||||
const getNewLog: GetNewLogFunction =
|
||||
@@ -92,6 +98,10 @@ export class Service extends DatabaseService<Model> {
|
||||
log.triggeredByIncidentId = options.triggeredByIncidentId;
|
||||
}
|
||||
|
||||
if (options.triggeredByAlertId) {
|
||||
log.triggeredByAlertId = options.triggeredByAlertId;
|
||||
}
|
||||
|
||||
return log;
|
||||
};
|
||||
|
||||
@@ -105,6 +115,16 @@ export class Service extends DatabaseService<Model> {
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
UserNotificationEventType.AlertCreated ===
|
||||
options.userNotificationEventType &&
|
||||
!options.triggeredByAlertId
|
||||
) {
|
||||
throw new BadDataException(
|
||||
"triggeredByAlertId is required when userNotificationEventType is IncidentCreated",
|
||||
);
|
||||
}
|
||||
|
||||
const usersInRule: Array<OnCallDutyPolicyEscalationRuleUser> =
|
||||
await OnCallDutyPolicyEscalationRuleUserService.findBy({
|
||||
query: {
|
||||
@@ -120,6 +140,8 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Found users in rule: ${JSON.stringify(usersInRule)}`);
|
||||
|
||||
const teamsInRule: Array<OnCallDutyPolicyEscalationRuleTeam> =
|
||||
await OnCallDutyPolicyEscalationRuleTeamService.findBy({
|
||||
query: {
|
||||
@@ -135,6 +157,8 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Found teams in rule: ${JSON.stringify(teamsInRule)}`);
|
||||
|
||||
const schedulesInRule: Array<OnCallDutyPolicyEscalationRuleSchedule> =
|
||||
await OnCallDutyPolicyEscalationRuleScheduleService.findBy({
|
||||
query: {
|
||||
@@ -150,7 +174,7 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
// get unique users and notify all the users.
|
||||
logger.debug(`Found schedules in rule: ${JSON.stringify(schedulesInRule)}`);
|
||||
|
||||
type StartUserNotificationRuleExecutionFunction = (
|
||||
userId: ObjectID,
|
||||
@@ -164,7 +188,9 @@ export class Service extends DatabaseService<Model> {
|
||||
teamId: ObjectID | null,
|
||||
scheduleId: ObjectID | null,
|
||||
): Promise<void> => {
|
||||
// no users in this rule. Skipping.
|
||||
logger.debug(
|
||||
`Starting notification rule execution for userId: ${userId.toString()}`,
|
||||
);
|
||||
let log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage = "Sending notification to user.";
|
||||
log.status = OnCallDutyExecutionLogTimelineStatus.Executing;
|
||||
@@ -189,6 +215,7 @@ export class Service extends DatabaseService<Model> {
|
||||
{
|
||||
userNotificationEventType: options.userNotificationEventType!,
|
||||
triggeredByIncidentId: options.triggeredByIncidentId || undefined,
|
||||
triggeredByAlertId: options.triggeredByAlertId || undefined,
|
||||
onCallPolicyExecutionLogId: options.onCallPolicyExecutionLogId,
|
||||
onCallPolicyId: options.onCallPolicyId,
|
||||
onCallPolicyEscalationRuleId: ruleId,
|
||||
@@ -220,7 +247,6 @@ export class Service extends DatabaseService<Model> {
|
||||
null,
|
||||
);
|
||||
} else {
|
||||
// no users in this rule. Skipping.
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage =
|
||||
"Skipped because notification sent to this user already.";
|
||||
@@ -247,7 +273,6 @@ export class Service extends DatabaseService<Model> {
|
||||
uniqueUserIds.push(userRule.userId!);
|
||||
await startUserNotificationRuleExecution(userRule.userId!, null, null);
|
||||
} else {
|
||||
// no users in this rule. Skipping.
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage =
|
||||
"Skipped because notification sent to this user already.";
|
||||
@@ -264,23 +289,16 @@ export class Service extends DatabaseService<Model> {
|
||||
}
|
||||
|
||||
for (const scheduleRule of schedulesInRule) {
|
||||
// get layers and users in this schedule and find a user to notify.
|
||||
|
||||
const userIdInSchedule: ObjectID | null =
|
||||
await OnCallDutyPolicyScheduleService.getCurrentUserIdInSchedule(
|
||||
scheduleRule.onCallDutyPolicyScheduleId!,
|
||||
);
|
||||
|
||||
if (!userIdInSchedule) {
|
||||
// no user active in this schedule. Skipping.
|
||||
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
|
||||
log.statusMessage =
|
||||
"Skipped because no active users are found in this schedule.";
|
||||
|
||||
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
||||
|
||||
log.onCallDutyScheduleId = scheduleRule.onCallDutyPolicyScheduleId!;
|
||||
|
||||
await OnCallDutyPolicyExecutionLogTimelineService.create({
|
||||
@@ -305,7 +323,6 @@ export class Service extends DatabaseService<Model> {
|
||||
scheduleRule.onCallDutyPolicyScheduleId!,
|
||||
);
|
||||
} else {
|
||||
// no users in this rule. Skipping.
|
||||
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
||||
log.statusMessage =
|
||||
"Skipped because notification sent to this user already.";
|
||||
@@ -323,7 +340,6 @@ export class Service extends DatabaseService<Model> {
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -335,6 +351,8 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
logger.debug(`Completed rule execution for ruleId: ${ruleId.toString()}`);
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import CreateBy from "../Types/Database/CreateBy";
|
||||
import { OnCreate } from "../Types/Database/Hooks";
|
||||
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import OnCallDutyPolicyEscalationRuleService from "./OnCallDutyPolicyEscalationRuleService";
|
||||
import OnCallDutyPolicyStatus from "../../Types/OnCallDutyPolicy/OnCallDutyPolicyStatus";
|
||||
@@ -7,6 +7,16 @@ import UserNotificationEventType from "../../Types/UserNotification/UserNotifica
|
||||
import OnCallDutyPolicyEscalationRule from "Common/Models/DatabaseModels/OnCallDutyPolicyEscalationRule";
|
||||
import Model from "Common/Models/DatabaseModels/OnCallDutyPolicyExecutionLog";
|
||||
import { IsBillingEnabled } from "../EnvironmentConfig";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import { Blue500, Green500, Red500, Yellow500 } from "../../Types/BrandColors";
|
||||
import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
|
||||
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import Color from "../../Types/Color";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
import BadDataException from "../../Types/Exception/BadDataException";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
@@ -32,6 +42,49 @@ export class Service extends DatabaseService<Model> {
|
||||
_onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
if (createdItem.triggeredByIncidentId || createdItem.triggeredByAlertId) {
|
||||
const onCallPolicy: OnCallDutyPolicy | null =
|
||||
await OnCallDutyPolicyService.findOneById({
|
||||
id: createdItem.onCallDutyPolicyId!,
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (onCallPolicy && onCallPolicy.id) {
|
||||
const feedInfoInMarkdown: string = `**On Call Policy Started Executing:** On Call Policy **${onCallPolicy.name}** started executing. Users on call on this policy will now be notified.`;
|
||||
|
||||
if (
|
||||
onCallPolicy &&
|
||||
onCallPolicy.id &&
|
||||
createdItem.triggeredByIncidentId
|
||||
) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: createdItem.triggeredByIncidentId,
|
||||
projectId: createdItem.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.OnCallPolicy,
|
||||
displayColor: Yellow500,
|
||||
feedInfoInMarkdown: feedInfoInMarkdown,
|
||||
});
|
||||
}
|
||||
|
||||
if (onCallPolicy && onCallPolicy.id && createdItem.triggeredByAlertId) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: createdItem.triggeredByAlertId,
|
||||
projectId: createdItem.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.OnCallPolicy,
|
||||
displayColor: Yellow500,
|
||||
feedInfoInMarkdown: feedInfoInMarkdown,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get execution rules in this policy adn execute the first rule.
|
||||
const executionRule: OnCallDutyPolicyEscalationRule | null =
|
||||
await OnCallDutyPolicyEscalationRuleService.findOneBy({
|
||||
@@ -60,12 +113,27 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
let userNotificationEventType: UserNotificationEventType | null = null;
|
||||
|
||||
if (createdItem.triggeredByIncidentId) {
|
||||
userNotificationEventType = UserNotificationEventType.IncidentCreated;
|
||||
}
|
||||
|
||||
if (createdItem.triggeredByAlertId) {
|
||||
userNotificationEventType = UserNotificationEventType.AlertCreated;
|
||||
}
|
||||
|
||||
if (!userNotificationEventType) {
|
||||
throw new BadDataException("Invalid userNotificationEventType");
|
||||
}
|
||||
|
||||
await OnCallDutyPolicyEscalationRuleService.startRuleExecution(
|
||||
executionRule.id!,
|
||||
{
|
||||
projectId: createdItem.projectId!,
|
||||
triggeredByIncidentId: createdItem.triggeredByIncidentId,
|
||||
userNotificationEventType: UserNotificationEventType.IncidentCreated,
|
||||
triggeredByAlertId: createdItem.triggeredByAlertId,
|
||||
userNotificationEventType: userNotificationEventType,
|
||||
onCallPolicyExecutionLogId: createdItem.id!,
|
||||
onCallPolicyId: createdItem.onCallDutyPolicyId!,
|
||||
},
|
||||
@@ -75,7 +143,7 @@ export class Service extends DatabaseService<Model> {
|
||||
id: createdItem.id!,
|
||||
data: {
|
||||
status: OnCallDutyPolicyStatus.Executing,
|
||||
statusMessage: "First escalation rule executed....",
|
||||
statusMessage: "First escalation rule executed...",
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
@@ -97,5 +165,111 @@ export class Service extends DatabaseService<Model> {
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
public getDisplayColorByStatus(status: OnCallDutyPolicyStatus): Color {
|
||||
switch (status) {
|
||||
case OnCallDutyPolicyStatus.Scheduled:
|
||||
return Blue500;
|
||||
case OnCallDutyPolicyStatus.Started:
|
||||
return Yellow500;
|
||||
case OnCallDutyPolicyStatus.Executing:
|
||||
return Yellow500;
|
||||
case OnCallDutyPolicyStatus.Completed:
|
||||
return Green500;
|
||||
case OnCallDutyPolicyStatus.Error:
|
||||
return Red500;
|
||||
default:
|
||||
return Blue500;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
_updatedItemIds: Array<ObjectID>,
|
||||
): Promise<OnUpdate<Model>> {
|
||||
// if status is updtaed then check if this on-call is related to the incident, if yes, then add to incident feed.
|
||||
if (onUpdate.updateBy.data.status && onUpdate.updateBy.query._id) {
|
||||
const id: ObjectID = onUpdate.updateBy.query._id! as ObjectID;
|
||||
|
||||
const onCalldutyPolicyExecutionLog: Model | null = await this.findOneById(
|
||||
{
|
||||
id: id,
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
onCallDutyPolicyId: true,
|
||||
status: true,
|
||||
statusMessage: true,
|
||||
triggeredByIncidentId: true,
|
||||
triggeredByAlertId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (
|
||||
onCalldutyPolicyExecutionLog &&
|
||||
(onCalldutyPolicyExecutionLog.triggeredByIncidentId ||
|
||||
onCalldutyPolicyExecutionLog.triggeredByAlertId)
|
||||
) {
|
||||
const onCallPolicy: OnCallDutyPolicy | null =
|
||||
await OnCallDutyPolicyService.findOneById({
|
||||
id: onCalldutyPolicyExecutionLog.onCallDutyPolicyId!,
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (onCallPolicy && onCallPolicy.id) {
|
||||
const moreInformationInMarkdown: string = `**Status:** ${onCalldutyPolicyExecutionLog.status}
|
||||
|
||||
**Message:** ${onCalldutyPolicyExecutionLog.statusMessage}`;
|
||||
|
||||
const feedInfoInMarkdown: string = `**On Call Policy Status Updated:**
|
||||
|
||||
On-call policy **${onCallPolicy.name}** status updated to **${onCalldutyPolicyExecutionLog.status}**`;
|
||||
|
||||
if (onCalldutyPolicyExecutionLog.triggeredByIncidentId) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId: onCalldutyPolicyExecutionLog.triggeredByIncidentId,
|
||||
projectId: onCalldutyPolicyExecutionLog.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.OnCallPolicy,
|
||||
displayColor: onCalldutyPolicyExecutionLog.status
|
||||
? this.getDisplayColorByStatus(
|
||||
onCalldutyPolicyExecutionLog.status,
|
||||
)
|
||||
: Blue500,
|
||||
moreInformationInMarkdown: moreInformationInMarkdown,
|
||||
feedInfoInMarkdown: feedInfoInMarkdown,
|
||||
});
|
||||
}
|
||||
|
||||
if (onCalldutyPolicyExecutionLog.triggeredByAlertId) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: onCalldutyPolicyExecutionLog.triggeredByAlertId,
|
||||
projectId: onCalldutyPolicyExecutionLog.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.OnCallPolicy,
|
||||
displayColor: onCalldutyPolicyExecutionLog.status
|
||||
? this.getDisplayColorByStatus(
|
||||
onCalldutyPolicyExecutionLog.status,
|
||||
)
|
||||
: Blue500,
|
||||
moreInformationInMarkdown: moreInformationInMarkdown,
|
||||
feedInfoInMarkdown: feedInfoInMarkdown,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
|
||||
@@ -1,9 +1,196 @@
|
||||
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
||||
import DatabaseService from "./DatabaseService";
|
||||
import Model from "Common/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline";
|
||||
import IncidentFeedService from "./IncidentFeedService";
|
||||
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
||||
import OnCallDutyExecutionLogTimelineStatus from "../../Types/OnCallDutyPolicy/OnCalDutyExecutionLogTimelineStatus";
|
||||
import { Blue500, Green500, Red500, Yellow500 } from "../../Types/BrandColors";
|
||||
import Color from "../../Types/Color";
|
||||
import ObjectID from "../../Types/ObjectID";
|
||||
import logger from "../Utils/Logger";
|
||||
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
||||
import AlertFeedService from "./AlertFeedService";
|
||||
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
super(Model);
|
||||
}
|
||||
|
||||
public getColorBasedOnStatus(
|
||||
status: OnCallDutyExecutionLogTimelineStatus,
|
||||
): Color {
|
||||
switch (status) {
|
||||
case OnCallDutyExecutionLogTimelineStatus.Started:
|
||||
return Blue500;
|
||||
case OnCallDutyExecutionLogTimelineStatus.Executing:
|
||||
return Yellow500;
|
||||
case OnCallDutyExecutionLogTimelineStatus.Error:
|
||||
return Red500;
|
||||
case OnCallDutyExecutionLogTimelineStatus.NotificationSent:
|
||||
return Green500;
|
||||
case OnCallDutyExecutionLogTimelineStatus.Skipped:
|
||||
return Red500;
|
||||
case OnCallDutyExecutionLogTimelineStatus.SuccessfullyAcknowledged:
|
||||
return Green500;
|
||||
default:
|
||||
return Blue500;
|
||||
}
|
||||
}
|
||||
|
||||
public async addToIncidentOrAlertFeed(data: {
|
||||
onCallDutyPolicyExecutionLogTimelineId: ObjectID;
|
||||
}): Promise<void> {
|
||||
logger.debug(
|
||||
"OnCallDutyPolicyExecutionLogTimelineService.addToIncidentFeed",
|
||||
);
|
||||
|
||||
const onCallDutyPolicyExecutionLogTimeline: Model | null =
|
||||
await this.findOneById({
|
||||
id: data.onCallDutyPolicyExecutionLogTimelineId,
|
||||
select: {
|
||||
_id: true,
|
||||
onCallDutyPolicyId: true,
|
||||
triggeredByIncidentId: true,
|
||||
triggeredByAlertId: true,
|
||||
projectId: true,
|
||||
status: true,
|
||||
statusMessage: true,
|
||||
alertSentToUserId: true,
|
||||
onCallDutyPolicy: {
|
||||
name: true,
|
||||
_id: true,
|
||||
},
|
||||
alertSentToUser: {
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
onCallDutyPolicyEscalationRule: {
|
||||
name: true,
|
||||
_id: true,
|
||||
},
|
||||
onCallDutySchedule: {
|
||||
name: true,
|
||||
_id: true,
|
||||
},
|
||||
isAcknowledged: true,
|
||||
acknowledgedAt: true,
|
||||
userBelongsToTeam: {
|
||||
name: true,
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug("OnCallDutyPolicyExecutionLogTimeline: ");
|
||||
logger.debug(onCallDutyPolicyExecutionLogTimeline);
|
||||
|
||||
if (!onCallDutyPolicyExecutionLogTimeline) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!onCallDutyPolicyExecutionLogTimeline.triggeredByIncidentId &&
|
||||
!onCallDutyPolicyExecutionLogTimeline.triggeredByAlertId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
onCallDutyPolicyExecutionLogTimeline.onCallDutyPolicy &&
|
||||
onCallDutyPolicyExecutionLogTimeline.onCallDutyPolicy.id
|
||||
) {
|
||||
const status: OnCallDutyExecutionLogTimelineStatus =
|
||||
onCallDutyPolicyExecutionLogTimeline.status!;
|
||||
|
||||
logger.debug("Status: " + status);
|
||||
|
||||
if (
|
||||
status &&
|
||||
(status === OnCallDutyExecutionLogTimelineStatus.Skipped ||
|
||||
status === OnCallDutyExecutionLogTimelineStatus.Error ||
|
||||
status ===
|
||||
OnCallDutyExecutionLogTimelineStatus.SuccessfullyAcknowledged ||
|
||||
status === OnCallDutyExecutionLogTimelineStatus.NotificationSent)
|
||||
) {
|
||||
const displayColor: Color = status
|
||||
? this.getColorBasedOnStatus(status)
|
||||
: Blue500;
|
||||
|
||||
const feedInfoInMarkdown: string = `**On-call alert ${status} to ${onCallDutyPolicyExecutionLogTimeline.alertSentToUser?.name?.toString().trim()}**
|
||||
|
||||
The on-call policy **${onCallDutyPolicyExecutionLogTimeline.onCallDutyPolicy.name}** has been triggered. The escalation rule **${onCallDutyPolicyExecutionLogTimeline.onCallDutyPolicyEscalationRule?.name}** ${onCallDutyPolicyExecutionLogTimeline.onCallDutySchedule?.name ? String(" and schedule **" + onCallDutyPolicyExecutionLogTimeline.onCallDutySchedule?.name + "**") : ""} were applied. The user **${onCallDutyPolicyExecutionLogTimeline.alertSentToUser?.name}** (${onCallDutyPolicyExecutionLogTimeline.alertSentToUser?.email}) was alerted. The status of this alert is **${status}** with the message: \`${onCallDutyPolicyExecutionLogTimeline.statusMessage}\`. ${onCallDutyPolicyExecutionLogTimeline.userBelongsToTeam?.name ? "The alert was sent because the user belogs to the team **" + onCallDutyPolicyExecutionLogTimeline.userBelongsToTeam?.name + "**" : ""} ${onCallDutyPolicyExecutionLogTimeline.isAcknowledged ? "The alert was acknowledged at **" + onCallDutyPolicyExecutionLogTimeline.acknowledgedAt + "**" : ""}`;
|
||||
|
||||
logger.debug("Feed Info in Markdown: " + feedInfoInMarkdown);
|
||||
|
||||
if (onCallDutyPolicyExecutionLogTimeline.triggeredByIncidentId) {
|
||||
await IncidentFeedService.createIncidentFeed({
|
||||
incidentId:
|
||||
onCallDutyPolicyExecutionLogTimeline.triggeredByIncidentId,
|
||||
projectId: onCallDutyPolicyExecutionLogTimeline.projectId!,
|
||||
incidentFeedEventType: IncidentFeedEventType.OnCallPolicy,
|
||||
displayColor: displayColor,
|
||||
feedInfoInMarkdown: feedInfoInMarkdown,
|
||||
});
|
||||
}
|
||||
|
||||
if (onCallDutyPolicyExecutionLogTimeline.triggeredByAlertId) {
|
||||
await AlertFeedService.createAlertFeed({
|
||||
alertId: onCallDutyPolicyExecutionLogTimeline.triggeredByAlertId,
|
||||
projectId: onCallDutyPolicyExecutionLogTimeline.projectId!,
|
||||
alertFeedEventType: AlertFeedEventType.OnCallPolicy,
|
||||
displayColor: displayColor,
|
||||
feedInfoInMarkdown: feedInfoInMarkdown,
|
||||
});
|
||||
}
|
||||
|
||||
logger.debug("Incident Feed created");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
_onCreate: OnCreate<Model>,
|
||||
createdItem: Model,
|
||||
): Promise<Model> {
|
||||
logger.debug("OnCallDutyPolicyExecutionLogTimelineService.onCreateSuccess");
|
||||
logger.debug(createdItem);
|
||||
|
||||
await this.addToIncidentOrAlertFeed({
|
||||
onCallDutyPolicyExecutionLogTimelineId: createdItem.id!,
|
||||
});
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
protected override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
_updatedItemIds: Array<ObjectID>,
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (onUpdate.updateBy.query) {
|
||||
const updatedItems: Array<Model> = await this.findBy({
|
||||
query: onUpdate.updateBy.query,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
skip: 0,
|
||||
});
|
||||
|
||||
for (const updatedItem of updatedItems) {
|
||||
await this.addToIncidentOrAlertFeed({
|
||||
onCallDutyPolicyExecutionLogTimelineId: updatedItem.id as ObjectID,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
}
|
||||
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