Compare commits

..

292 Commits

Author SHA1 Message Date
Frank Elsinga
2bd51a3145 Merge branch 'master' into extracted-grpc-monitor 2024-06-07 16:00:35 +02:00
Frank Elsinga
6c49b53d6a Reverted accidental import changes 2024-06-07 15:58:24 +02:00
Frank Elsinga
334e37eaa0 migrated grpc keyword to the newer monitoringtype 2024-06-04 05:34:13 +02:00
Frank Elsinga
4794f9eb0b Removed the last reminents of cypress (#4819) 2024-06-04 03:09:52 +02:00
Frank Elsinga
77d82ec30f removed the last reminents of cypress 2024-06-04 03:02:34 +02:00
Frank Elsinga
c7b83e729b Fixed smspartner not having fully working translations (#4816) 2024-06-04 01:28:33 +02:00
Frank Elsinga
f43fe53d28 Fixed smspartner not having fully working translations 2024-06-04 01:10:20 +02:00
Frank Elsinga
10ebdcacaa Fix: Use retryInterval when a monitor is DOWN (#4476) 2024-06-03 21:47:43 +02:00
Frank Elsinga
a00b4ed285 Feat: Add background color change on hover to nav links (#4494) 2024-06-03 21:06:23 +02:00
Frank Elsinga
a26d93ac52 Merge branch 'master' into nav-link-hover 2024-06-03 21:04:50 +02:00
DevMirza
c919d2c990 fix(ci): Prevent ARM runner from running in Forks (#4803) 2024-05-30 14:46:04 +08:00
Frank Elsinga
40d24e7837 feat: update feishu notification template (#4800) 2024-05-29 18:19:53 +02:00
nino
30bf7a5e23 fix: update Feishu notification provider configuration 2024-05-29 22:22:05 +08:00
nino
4e63d00007 feat: update feishu notification template 2024-05-29 18:20:33 +08:00
Frank Elsinga
9f35290c68 made sure that the Set up a Docker Builder section in the contribution guide is layouted like the rest 2024-05-29 11:03:37 +02:00
Frank Elsinga
11007823e7 feat: added HTTP method option for push monitor (#1991) 2024-05-24 10:26:58 +02:00
Stefan Ottosson
9ce0911e34 Merge branch 'master' into feature/http-method-push-monitor 2024-05-24 09:05:11 +02:00
Stefan Ottosson
df663a81cd Update src/pages/EditMonitor.vue
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-24 09:04:12 +02:00
Stefan Ottosson
8b648a3ed1 Revert "fix: hide body options for monitor type push"
This reverts commit e670b5f4cf.
2024-05-24 08:29:22 +02:00
Stefan Ottosson
9c7aa13190 fix: remove check that method is correct 2024-05-24 08:29:09 +02:00
Stefan Ottosson
823aeda9fe Revert "fix: update some examples"
This reverts commit b2ede38269.
2024-05-24 08:26:28 +02:00
Frank Elsinga
1590ca6c02 made sure that json-query for the mqtt monitor is translated properly (#4791) 2024-05-23 20:37:02 +02:00
Frank Elsinga
359e961aa7 Fixed flipflopping between having needs:resolve-merge-conflict and not having needs:resolve-merge-conflict 2024-05-23 20:16:37 +02:00
Stefan Ottosson
e670b5f4cf fix: hide body options for monitor type push 2024-05-23 17:49:18 +02:00
Stefan Ottosson
b2ede38269 fix: update some examples 2024-05-23 17:42:36 +02:00
Stefan Ottosson
1ac5696463 Merge branch 'master' into feature/http-method-push-monitor
# Conflicts:
#	src/pages/EditMonitor.vue
2024-05-23 17:34:45 +02:00
Frank Elsinga
63b8c52a65 made sure that json-query for the mqtt monitor is translated properly 2024-05-23 14:48:12 +02:00
Frank Elsinga
4df71af34f Update en.json: "setup" -> "set up" (#4436) 2024-05-23 14:13:53 +02:00
Frank Elsinga
07a0718272 Translation unpin incident -> delete incident (#4565) 2024-05-23 14:13:28 +02:00
Frank Elsinga
46e4b16a7e Translations Update from Weblate (#4394) 2024-05-23 14:10:39 +02:00
TheSkout001
5473bc9689 Translated using Weblate (Russian)
Currently translated at 89.4% (826 of 923 strings)

Co-authored-by: TheSkout001 <daniil.afg@yandex.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
dnlweijers
9f07011200 Translated using Weblate (Dutch)
Currently translated at 100.0% (923 of 923 strings)

Co-authored-by: dnlweijers <dnlweijers5@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
Ilkka Myller
029944c655 Translated using Weblate (Finnish)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (923 of 923 strings)

Co-authored-by: Ilkka Myller <ilkka.myller@nodefield.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fi/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
glauder
b02a4055b8 Translated using Weblate (Russian)
Currently translated at 89.4% (826 of 923 strings)

Translated using Weblate (Russian)

Currently translated at 96.2% (888 of 923 strings)

Co-authored-by: glauder <glauder@mail.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
Bram Van Mol
82c59da16a Translated using Weblate (Dutch)
Currently translated at 99.5% (919 of 923 strings)

Co-authored-by: Bram Van Mol <bram.vanmol@cawantwerpen.be>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
gclme
888585dcef Translated using Weblate (Malayalam)
Currently translated at 5.3% (49 of 923 strings)

Translated using Weblate (Malayalam)

Currently translated at 3.6% (34 of 923 strings)

Co-authored-by: gclme <github@cloudlink.media>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ml/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
TheSkout001
dd1eab1c6c Translated using Weblate (Russian)
Currently translated at 96.0% (887 of 923 strings)

Co-authored-by: TheSkout001 <daniil.afg@yandex.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
Ilkka Myller
a56c4ffa36 Translated using Weblate (Finnish)
Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (English)

Currently translated at 100.0% (923 of 923 strings)

Co-authored-by: Ilkka Myller <ilkka@myller.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fi/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
eballester
4e49dccd15 Translated using Weblate (Catalan)
Currently translated at 7.8% (72 of 923 strings)

Co-authored-by: eballester <eduard.ballester@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ca/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
Rumplin
96560fff20 Translated using Weblate (Slovenian)
Currently translated at 65.6% (606 of 923 strings)

Co-authored-by: Rumplin <rumplin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
Karim guezlane
f5c59f403d Translated using Weblate (Arabic (ar_SY))
Currently translated at 71.7% (662 of 923 strings)

Co-authored-by: Karim guezlane <k.guezlane@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar_SY/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:58 +00:00
Adrian \"Rootovsky\" Korzeniowski
798be2a4a8 Translated using Weblate (Polish)
Currently translated at 96.6% (891 of 922 strings)

Co-authored-by: Adrian \"Rootovsky\" Korzeniowski <adikorzeniowski@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Luc Dogge
ed69842939 Translated using Weblate (Dutch)
Currently translated at 99.1% (914 of 922 strings)

Co-authored-by: Luc Dogge <l.j.dogge@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Michal
5e1d2736eb Translated using Weblate (Czech)
Currently translated at 99.6% (919 of 922 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
AnnAngela
9a83a9d6e7 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (945 of 945 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (921 of 922 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
凯观生活
325f3520e1 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (921 of 922 strings)

Co-authored-by: 凯观生活 <niujinkai@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Facundo Ortiz Gallego
52036394a5 Translated using Weblate (Spanish)
Currently translated at 97.5% (890 of 912 strings)

Co-authored-by: Facundo Ortiz Gallego <faq.ortiz@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Marco
b112afba9b Translated using Weblate (German)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (German)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (German)

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (German)

Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (German)

Currently translated at 100.0% (912 of 912 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Justman100
d0e1e40717 Translated using Weblate (German)
Currently translated at 100.0% (912 of 912 strings)

Co-authored-by: Justman100 <justmegaliga10000@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
aditya wahyudi
fff47248f0 Translated using Weblate (Indonesian)
Currently translated at 99.4% (907 of 912 strings)

Co-authored-by: aditya wahyudi <aditbaco@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Zandor Smith
48a1314de1 Translated using Weblate (Dutch)
Currently translated at 100.0% (912 of 912 strings)

Co-authored-by: Zandor Smith <info@zsinfo.nl>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Piet Jan
9a204fbfa9 Translated using Weblate (German)
Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Dutch)

Currently translated at 98.4% (898 of 912 strings)

Co-authored-by: Piet Jan <piet2001@fireman.net>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Buchtič
9e6e21243f Translated using Weblate (Czech)
Currently translated at 100.0% (912 of 912 strings)

Co-authored-by: Buchtič <martin.buchta@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
gabichan
e355452b5c Translated using Weblate (Spanish)
Currently translated at 96.9% (884 of 912 strings)

Co-authored-by: gabichan <gabichan@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Lucas Elias Baccan
0279331326 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (English)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.7% (910 of 912 strings)

Co-authored-by: Lucas Elias Baccan <naccabbaccan@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
gmesml
ec66dca19b Translated using Weblate (Albanian)
Currently translated at 27.8% (254 of 912 strings)

Co-authored-by: gmesml <gme@sml.at>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sq/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
stanol
d36e6b09ae Translated using Weblate (Ukrainian)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (917 of 917 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (912 of 912 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
pashanchannel
f4e80dbd02 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (912 of 912 strings)

Co-authored-by: pashanchannel <pavlonimetrons@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
basmulder03
7dc17bd796 Translated using Weblate (Dutch)
Currently translated at 100.0% (889 of 889 strings)

Co-authored-by: basmulder03 <bas.d.mulder@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
amin Kazemi
68f9dfbcef Translated using Weblate (Persian)
Currently translated at 100.0% (889 of 889 strings)

Co-authored-by: amin Kazemi <amin.kazemi.ir@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Ömer Faruk Genç
f85c9b6b1d Translated using Weblate (Turkish)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Marco Beretta
75426ffbe7 Translated using Weblate (Italian)
Currently translated at 73.0% (648 of 887 strings)

Co-authored-by: Marco Beretta <marco13beretta@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:57 +00:00
Michal
05c67d07c3 Translated using Weblate (Czech)
Currently translated at 99.8% (911 of 912 strings)

Translated using Weblate (Czech)

Currently translated at 99.4% (884 of 889 strings)

Translated using Weblate (Czech)

Currently translated at 99.5% (883 of 887 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
AnnAngela
e6c85d3afc Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (907 of 907 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
stanol
5d06378c11 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Gunnar Norin
3c85d86cda Translated using Weblate (Swedish)
Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: Gunnar Norin <gunnar.norin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sv/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
René Vlugt
6fdcb1b909 Translated using Weblate (Dutch)
Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: René Vlugt <vashiru@pm.me>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
flyingfeng
1527a15dde Translated using Weblate (Japanese)
Currently translated at 62.9% (558 of 887 strings)

Co-authored-by: flyingfeng <2917268843@qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
MrEddX
5281dd47f7 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (917 of 917 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (907 of 907 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (887 of 887 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
DevMirza
43c10287a4 Translated using Weblate (Urdu)
Currently translated at 61.6% (546 of 885 strings)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Akashubham09
721234b5f6 Translated using Weblate (English)
Currently translated at 99.8% (884 of 885 strings)

Co-authored-by: Akashubham09 <Shubhamkumar56169@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
demonisius
ac4e1d890c Translated using Weblate (Russian)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: demonisius <demonisius@mail.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Peter Paul
584c8b05ca Translated using Weblate (Afrikaans)
Currently translated at 6.8% (61 of 885 strings)

Added translation using Weblate (Afrikaans)

Co-authored-by: Peter Paul <henco@techguide.co.za>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/af/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
JC
25b17e5dde Translated using Weblate (Catalan)
Currently translated at 4.7% (42 of 885 strings)

Co-authored-by: JC <jjsuscc@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ca/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Ismael
17424f4e74 Translated using Weblate (Spanish)
Currently translated at 99.8% (884 of 885 strings)

Co-authored-by: Ismael <ismaellambertymuniz@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Marco
476d869321 Translated using Weblate (German (Switzerland))
Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (German)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (German)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (German)

Currently translated at 100.0% (907 of 907 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (907 of 907 strings)

Translated using Weblate (German)

Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (German)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (German)

Currently translated at 100.0% (887 of 887 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (887 of 887 strings)

Translated using Weblate (German)

Currently translated at 100.0% (887 of 887 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (887 of 887 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Finn
c9a32bcdb2 Translated using Weblate (German)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Finn <git@finn.gg>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Aindriú Mac Giolla Eoin
ca28bee05f Translated using Weblate (Irish)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Irish)

Currently translated at 96.4% (890 of 923 strings)

Translated using Weblate (Irish)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Irish)

Currently translated at 80.0% (708 of 885 strings)

Translated using Weblate (Irish)

Currently translated at 47.4% (420 of 885 strings)

Translated using Weblate (Irish)

Currently translated at 7.7% (69 of 885 strings)

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ga/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
John Doe
57c8656d32 Translated using Weblate (Bavarian)
Currently translated at 0.4% (4 of 885 strings)

Added translation using Weblate (Bavarian)

Co-authored-by: John Doe <weplaet@candymail.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bar/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:56 +00:00
Louis Lam
a7f7aa1ce9 Added translation using Weblate (Irish)
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2024-05-23 02:35:55 +00:00
letterlock
6bf5d97d66 Translated using Weblate (Danish)
Currently translated at 71.6% (634 of 885 strings)

Co-authored-by: letterlock <max@letterlock.eu>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Cosmo Abdon
1c438c91d5 Translated using Weblate (Portuguese (Portugal))
Currently translated at 50.8% (450 of 885 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Cosmo Abdon <cosmo.webp2@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_PT/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Adam Stachowicz
561d307fb8 Translated using Weblate (Polish)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Filip Rojek
49605cd061 Translated using Weblate (Czech)
Currently translated at 99.5% (881 of 885 strings)

Co-authored-by: Filip Rojek <filip@filiprojek.cz>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Kisem
320d9712cd Translated using Weblate (Hungarian)
Currently translated at 89.8% (795 of 885 strings)

Co-authored-by: Kisem <kiss.m.aron@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Mohannad Faihan Otaibi
b0a855e218 Translated using Weblate (Arabic)
Currently translated at 82.9% (734 of 885 strings)

Co-authored-by: Mohannad Faihan Otaibi <mohannad.otaibi@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Máté Tallósi
04d46b6a43 Translated using Weblate (Hungarian)
Currently translated at 89.8% (795 of 885 strings)

Translated using Weblate (Hungarian)

Currently translated at 87.7% (777 of 885 strings)

Co-authored-by: Máté Tallósi <tallosimate@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Jochem Pluim
50c8dd95c2 Translated using Weblate (Dutch)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Jochem Pluim <jochem@pluim.nu>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Jonne Saloranta
668aa49343 Translated using Weblate (Finnish)
Currently translated at 76.3% (676 of 885 strings)

Co-authored-by: Jonne Saloranta <saloranta.jonne@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fi/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
vahidxo
e2a2234504 Translated using Weblate (Persian)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: vahidxo <s.v.morsali@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Aji Priyo Wibowo
8ccf536498 Translated using Weblate (Indonesian)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Aji Priyo Wibowo <aji.wibowo@ionmobility.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Patrick van Halderen
f828fee27e Translated using Weblate (Dutch)
Currently translated at 99.6% (882 of 885 strings)

Co-authored-by: Patrick van Halderen <patrick@vanhalderen.net>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Ivan Bratović
5df75b37ab Translated using Weblate (Croatian)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Ivan Bratović <ivanbratovic4@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hr/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Dan Misener
b1f2e25188 Translated using Weblate (English)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Dan Misener <dan@misener.org>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
kindercat
c9eb483a58 Translated using Weblate (Romanian)
Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (907 of 907 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (English)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (887 of 887 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: kindercat <156439718+kindercat@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ro/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Alex Javadi
22d97318c2 Translated using Weblate (Persian)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Alex Javadi <15309978+aljvdi@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Alejandro Vásquez Neira
1d75d7cace Translated using Weblate (Spanish)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Alejandro Vásquez Neira <alejandro.vasquez@neurotools.cl>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:55 +00:00
Cyril59310
5c72176ee4 Translated using Weblate (French)
Currently translated at 100.0% (940 of 940 strings)

Translated using Weblate (French)

Currently translated at 100.0% (936 of 936 strings)

Translated using Weblate (French)

Currently translated at 100.0% (932 of 932 strings)

Translated using Weblate (French)

Currently translated at 100.0% (923 of 923 strings)

Translated using Weblate (French)

Currently translated at 100.0% (922 of 922 strings)

Translated using Weblate (French)

Currently translated at 100.0% (917 of 917 strings)

Translated using Weblate (French)

Currently translated at 100.0% (914 of 914 strings)

Translated using Weblate (French)

Currently translated at 100.0% (912 of 912 strings)

Translated using Weblate (French)

Currently translated at 100.0% (908 of 908 strings)

Translated using Weblate (French)

Currently translated at 100.0% (907 of 907 strings)

Translated using Weblate (French)

Currently translated at 100.0% (894 of 894 strings)

Translated using Weblate (French)

Currently translated at 100.0% (889 of 889 strings)

Translated using Weblate (French)

Currently translated at 100.0% (887 of 887 strings)

Translated using Weblate (French)

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (French)

Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2024-05-23 02:35:54 +00:00
Nicolas Verlhiac
b1e95968c0 New notification provider: SMS Partner API (#4769)
Co-authored-by: Nicolas Verlhiac <nicolas@novariom.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-22 22:53:49 +02:00
Louis Lam
88b7c047a8 Switch back to TryGhost/node-sqlite3 from louislam/node-sqlite3 (#4773) 2024-05-20 10:42:37 +08:00
Gauvino
533af0f56c feat: Add merge conflict labeler workflow (#4694)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-20 00:16:42 +02:00
HdroguettA
daca38a554 Ignore TLS/SSL error for Redis (#3878)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-19 23:34:01 +02:00
Furkan İ
55b2d4b907 Add Bitrix24 Webhook notification (#3620)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
2024-05-19 23:33:32 +02:00
Damon
168d1ca24f refactor: upload check label when monitor empty (#3661)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-19 23:17:09 +02:00
Jed Fox
668e8bafed Gray out label for up/down/maintenance labels when they are zero (#3037)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-19 23:01:14 +02:00
Nelson Chan
a581a85633 Feat: Use UptimeCalculator for PingChart (#4264)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-19 22:03:32 +02:00
Sebastian Lang
a3ac954140 Add support for custom mongodb commands (#4445)
Co-authored-by: Sebastian Lang <sebastian.lang@damovo.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-19 21:59:57 +02:00
Laurent Aupse
e856cb6007 Make auto refresh interval customizable (#4260)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-05-19 21:56:55 +02:00
TheDanniCraft
4e24e96dab [discord] thread/forum channel support (#4099) 2024-05-19 21:14:13 +02:00
Louis Lam
6bfb1be71a Improve MariaDB's connection (#4728) 2024-05-19 22:46:22 +08:00
jmolnar-comparative
237a6e8da9 chore: fixed a typo for internal, unused part of the file upload icon for status page (#4750) 2024-05-10 20:35:36 +02:00
Frank Elsinga
dbbc79a05a Fixed a typo introduced in #3836 (#4729)
Co-authored-by: Nelson Chan <3271800+chakflying@users.noreply.github.com>
2024-05-02 12:11:49 +08:00
Rakovskij Stanislav
9f2cf28a76 Making docker usage with localhost and external ip more clear (#3836)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-30 22:53:27 +02:00
Ezhil Shanmugham
988ba79679 feat: keephq notification provider (#4722) 2024-04-30 16:17:34 +02:00
Joschua Becker
19e8c75c3b SevenIO Notification Provider (#4219)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-27 23:40:59 +02:00
凯观生活
126d6cd912 Add the ability to notify @everyone in DingTalk notifications (#4718)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-27 17:16:39 +02:00
Louis Lam
c86706f189 1.23.13 changes merge to 2.0.0 (#4708) 2024-04-26 15:11:26 +08:00
Louis Lam
1d091739c8 Update server/model/monitor.js
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2024-04-26 15:01:03 +08:00
Louis Lam
27bcc968ec Update server/util-server.js
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2024-04-25 23:45:30 +08:00
Louis Lam
c0db036187 Update server/model/monitor.js
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2024-04-25 23:45:24 +08:00
Louis Lam
7da5b2311c Fix merge issue 2024-04-25 15:49:32 +08:00
Louis Lam
996db6281b Update dependencies and remove an empty file 2024-04-25 15:46:18 +08:00
Louis Lam
63a380326d Merge branch '1.23.X' into 1.23.13-to-2.0.0
# Conflicts:
#	.github/workflows/auto-test.yml
#	package-lock.json
#	package.json
#	server/database.js
#	server/model/monitor.js
#	server/monitor-types/real-browser-monitor-type.js
#	server/util-server.js
#	test/cypress/unit/i18n.spec.js
2024-04-25 15:42:53 +08:00
Louis Lam
2778929f74 Update to 1.23.13 2024-04-25 15:27:28 +08:00
Louis Lam
f71d35e53e Update dependencies 2024-04-25 15:26:49 +08:00
Nelson Chan
1490443618 Fix: Getting TLS certificate through proxy & prometheus update (#4700) 2024-04-24 14:37:17 +08:00
BigBoot
bab427f715 Add loginRequired SocketIO event (#4636) 2024-04-21 20:39:44 +02:00
Frank Elsinga
add5c128ce fix: Localisation-matching algorithm missing some edgecase (#4692) 2024-04-21 20:23:34 +08:00
Louis Lam
29575343ca Update CONTRIBUTING.md for how to set up a Docker builder (#4668)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-19 17:37:12 +08:00
Louis Lam
e797abd108 Update to 1.23.12 2024-04-19 01:17:13 +08:00
Louis Lam
7a9e2f5de6 Merge pull request from GHSA-23q2-5gf8-gjpp 2024-04-19 01:08:31 +08:00
Louis Lam
7b5d2a71ff Update dependencies 2024-04-18 20:48:07 +08:00
CoolCu
b25ac55a2f chore: fix some typos in comments (#4679)
Signed-off-by: CoolCu <coolcui@qq.com>
2024-04-16 16:59:07 +02:00
msrl2000
05606c69e7 Update i18n.js (#4666) 2024-04-10 21:49:19 +02:00
Nelson Chan
893278bd3d Feat: Use keylog event to obtain TLS certificate for better reliability [1.23.X] (#4630)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-06 18:43:08 +08:00
Adam Stachowicz
0e30ea830d fix: Update nodemailer to fix GHSA-9h6g-pr28-7cqp [1.23.X] (#4653) 2024-04-05 17:38:24 +02:00
Louis Lam
c67a2070b8 Update deps 2024-04-05 12:12:36 +08:00
Adam Stachowicz
9863a10321 fix: Update axios, @actions/github and dompurify [1.23.X] (#4652) 2024-04-05 11:47:46 +08:00
Edoardo Ridolfi
822ce5384b Add support for Whapi notification provider (#4323)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-03 02:22:01 +02:00
Merlin
937c8a9a7b New notification provider: CallMeBot API (#4605)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-04-02 21:39:45 +02:00
Daan Meijer
effd0197ac [Slack] restructure alert actions, add 'visit site' button (#3886)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Nelson Chan <3271800+chakflying@users.noreply.github.com>
2024-04-02 02:43:54 +02:00
Nelson Chan
ee7f8680c1 Fix: Add missing FK for monitor-tls-info table [1.23.X] (#4631) 2024-03-31 12:05:38 +08:00
Nelson Chan
08f75b0b99 Fix: Add missing FK for monitor-tls-info table (#4632) 2024-03-31 12:04:22 +08:00
Nelson Chan
c1301804d4 Fix: Fix CI on Windows Runner [1.23.X] (#4633) 2024-03-31 10:33:59 +08:00
Simon Nilsson
0923d05317 Cellsynt mobile services (#4625)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-03-29 16:27:54 +01:00
Chongyi Zheng
88187b66eb Drop Node.js 14 and 16 (#3747)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2024-03-28 07:30:33 +08:00
Nelson Chan
b8858f4605 Feat: Handle maintenance in UptimeCalculator (#4406)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-03-27 10:19:25 +08:00
Christoph Fichtmüller
49b6dacb4d Add gtxmessaging Notification Support (#4481)
Signed-off-by: Christoph Fichtmüller <cf@cfichtmueller.com>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-03-26 23:59:09 +01:00
Louis Lam
e927327bad Some minor changes for 2.0.0 (#4621) 2024-03-26 15:17:52 +08:00
DevMirza
45690a25a0 fix(ci): Fix for the Actions failing on Windows Runner (#4557) 2024-03-20 22:20:40 +08:00
Elliot Matson
5bc68fe0a7 Google chat cards (#3928)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-03-20 12:58:28 +01:00
OptimusGREEN
bc077cc536 add notification channel for home assistant (#4541)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Seb <144435+rmtsrc@users.noreply.github.com>
2024-03-18 23:31:37 +01:00
Frank Elsinga
975761b448 made sure to use Promise.allSettled instead of sleeping for 500ms after login (#4592) 2024-03-19 00:16:04 +08:00
Frank Elsinga
0e3b3a9ab8 Made sure that more of the async usages are awaited (#4574) 2024-03-15 15:02:55 +01:00
Frank Elsinga
a9a1cf1353 Chore: General notification reformatting (#3182)
- I unified where in file the name of `NotificationProvider.name` is placed
- I made sure that all the providers adhere to the signature of `NotificationProvider.send()`
- I made sure that all the providers use `okMsg` if returning success messages directly from the function.
  Here a discussion should be had:
  Should this be refactored into a constant of `NotificationProvider`? I could imagine that `NotificationProvider.SENDING_SUCCESSFULL`  could be a suitable alternative.
- I made sure all providers have the URL they `POST`/`GET` to be extraced into a variable.
  => refactored this way due to Nelsons suggestion
2024-03-14 14:21:15 +01:00
Frank Elsinga
bfd65ab6e3 Add Heii On-Call Notification Provider (#4485) 2024-03-11 20:51:34 +01:00
Frank Elsinga
1db750a2e1 Merge branch 'master' into hevans/add-heii-on-call-notification-provider 2024-03-11 20:49:42 +01:00
LeoThies
abd62a12e4 edit unpin to delete 2024-03-11 11:52:22 +01:00
Frank Elsinga
ca14c34977 Set mqtt-clientId to uptime-kuma_.. instead of mqttjs_.. (#4503) 2024-03-10 15:16:07 +01:00
Frank Elsinga
2a3a2201e6 make monitor start() and stop() async (#2830) 2024-03-09 23:36:00 +01:00
Frank Elsinga
6eef2192b0 Refactor MS-Teams notification to use AdaptiveCards (#4538) 2024-03-07 15:36:32 +01:00
taschenuhr
9789931edf Merge branch 'master' into feature/msteams-adaptivecards 2024-03-07 15:30:26 +01:00
taschenuhr
4aaa0b92fb fix test notification after method refactoring 2024-03-07 15:11:19 +01:00
Frank Elsinga
fdf562fe39 Test for db file existance instead of creating a new one in password-restet.js (#4519)
Test for db file existance instead of creating a new one in `password-restet.js`
2024-03-06 13:03:07 +01:00
Frank Elsinga
b385e81608 Improved helptext of how to send mail via the systems mail subsystem (#4477) 2024-03-05 19:40:45 +01:00
Frank Elsinga
e2239bc7b7 Merge branch 'master' into hevans/add-heii-on-call-notification-provider 2024-03-05 19:20:14 +01:00
Frank Elsinga
da92400401 [Ntfy] Only include action link if monitor url is defined #3274 (#4411) 2024-03-05 19:19:18 +01:00
Humberto Evans
daa59b812c Update en.json
Fix misspelled "Trigger"
2024-03-04 14:54:17 -08:00
Frank Elsinga
574705a4c3 Updated strings for LINE Messenger as changed in their developer portal (#4527) 2024-03-03 18:29:24 +01:00
Andi Pätzold
a0c62d8ab0 Fix: handle monitor names with slashes (#4472)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-03-03 17:59:38 +08:00
Huzaifa Azim
8fd713d642 migrate timezones-list lib to @vvo/tzdb issue #4479 (#4521) 2024-03-03 17:54:14 +08:00
Frank Elsinga
4c683da0dd Refactored the Can I create a pull request for Uptime Kuma section (#4545) 2024-03-03 17:45:35 +08:00
Frank Elsinga
507ff76728 More readable Contribution guide (#4525)
Co-authored-by: Nelson Chan <3271800+chakflying@users.noreply.github.com>
2024-03-03 17:44:53 +08:00
taschenuhr
8bd69d78a8 some more tweaking of the card content and notification summary 2024-02-28 17:41:00 +01:00
taschenuhr
cc09147b4b fix adding optional ActionSet 2024-02-28 16:31:47 +01:00
taschenuhr
b8941403d1 code cleanup 2024-02-28 16:30:48 +01:00
taschenuhr
5b87da94b3 push notificationMessage to card header and add action button to dashboard 2024-02-28 14:19:32 +01:00
Vista2003
9209210e7c Merge branch 'master' into master 2024-02-28 13:00:03 +00:00
Nelson Chan
c7b8bb9e4a Fix: Incorrect handling of status page not found (#4537) 2024-02-28 18:57:58 +08:00
taschenuhr
7756070c57 refactor MS-Teams notification to use adaptive cards 2024-02-28 09:47:14 +01:00
Louis Lam
d88e7702b9 Update axios from 0.27.x to 0.28.x (#4532) 2024-02-27 22:07:43 +08:00
Frank Elsinga
ee99ee9460 changed which translation we are using 2024-02-27 00:09:56 +01:00
Vista2003
800847d0df Correcting label to fit what it says on the page 2024-02-26 20:23:57 +00:00
Vista2003
3fd0c822d6 Removed trailing space 2024-02-25 16:31:25 +00:00
Vista2003
e74d6a7471 Fixing strings as reported on issue #4526 2024-02-25 10:35:32 +00:00
Huzaifa Azim
99dccd9e90 reset-password-issue-4518 2024-02-23 18:10:09 +05:00
Louis Lam
e61589d02e Add Vue DevTools (#4509) 2024-02-21 09:13:49 +08:00
NihadBadalov
17dfdacd93 Fix: Correct colors 2024-02-20 17:52:59 +01:00
Stefan Heine
6bfc58674a MQTT monitor, set the MQTT clientId to make it easier in the MQTT broker to identify where the connections are coming from 2024-02-19 07:57:34 +01:00
Stefan Heine
1b293f2754 MQTT monitor, set the MQTT clientId to make it easier in the MQTT broker to identify where the connections are coming from 2024-02-19 07:42:37 +01:00
Humberto Evans
9a52a8761c Apply suggestions from code review
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-02-16 15:08:59 -07:00
NihadBadalov
94154c49aa Feat: Change hover colors to shades of gray 2024-02-15 08:21:54 +01:00
Frank Elsinga
1fdb7e48ed Formatting fixes 2024-02-14 23:45:23 +01:00
Frank Elsinga
cc000117ca Updated the code to look more like the other notification providers 2024-02-14 23:41:35 +01:00
NihadBadalov
4d6ea433e6 Feat: Add background color change on hover to nav links 2024-02-14 22:51:06 +01:00
Frank Elsinga
cf2d603e27 Stale, incorrect issue template and cannot-reproduce Comments (#4490) 2024-02-14 13:43:31 +08:00
Humberto Evans
5a9c3ad353 move try/catch into main control flow and more from code review comments 2024-02-13 17:27:59 -08:00
Humberto Evans
4cdc8f344b Apply suggestions from code review
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-02-13 16:54:52 -08:00
Aindriú Mac Giolla Eoin
0efdfc4497 Added Irish language (#4487) 2024-02-13 19:44:53 +08:00
Humberto Evans
673f9a7744 get the linter to be happy with my vue file 2024-02-12 18:12:07 -08:00
Humberto Evans
f254940b64 spell things correctly 2024-02-12 18:01:06 -08:00
Humberto Evans
71dd5e2369 do not assume missing heartbeat is a test 2024-02-12 17:54:36 -08:00
Humberto Evans
09d249ca36 add form to NotificationDialog 2024-02-12 17:48:53 -08:00
Humberto Evans
5f25a75f65 remove line at end of file 2024-02-12 17:39:41 -08:00
Humberto Evans
92488290fa add newline at end of file 2024-02-12 17:38:50 -08:00
Humberto Evans
246316f55b Undo my overzelous linter 2024-02-12 17:24:42 -08:00
Humberto Evans
10659d07b2 add link to documentation explaining how to get id and token 2024-02-12 16:56:41 -08:00
Humberto Evans
80bdc455da lint 2024-02-12 16:31:58 -08:00
Humberto Evans
e8fada9386 set url to heii on call prod 2024-02-12 16:14:41 -08:00
Humberto Evans
93ac212aef Add Heii On-Call 2024-02-12 15:58:54 -08:00
Frank Elsinga
f37f55e06c Fixed lining issues introduced by code reivew 2024-02-11 22:44:57 +01:00
Frank Elsinga
87d7a780e3 changed the helptext a bit to make it more usefull for novice users 2024-02-11 22:40:47 +01:00
apio-sys
0fc372f558 #2793 2024-02-11 20:20:52 +01:00
Joris Le Blansch
67a13e1259 #2793 2024-02-11 20:03:17 +01:00
Frank Elsinga
81e465f418 Removed debug statement 2024-02-11 20:02:09 +01:00
Neel Bhanushali
a5d0f7a7db console added with double quotes and semicolons. console added with username so i can remove later 2024-02-11 21:42:20 +05:30
Neel Bhanushali
a16b42f98c poc done 2024-02-11 21:33:58 +05:30
Neel Bhanushali
65ff08b38e lower heartbeat interval when monitor is down #4025 2024-02-11 20:19:56 +05:30
Nelson Chan
56aa81e337 UI: Improve maintenace actions design (#4407) 2024-02-03 06:16:14 +08:00
Frank Elsinga
dc3abc68f0 Fixed type anotation 2024-01-30 17:54:04 +01:00
Frank Elsinga
89158be7de Merge branch 'master' into monitor_async_start_stop 2024-01-30 17:53:21 +01:00
Robert Martin
ac4355114a Update en.json
Grammar fix: "set up" should be two words when used as a verb
2024-01-29 22:14:06 -06:00
Louis Lam
3cea7d4eb2 Update dependencies 2024-01-30 01:38:45 +08:00
Nelson Chan
2bccae415f Feat: Show monitor ID in Details (#4331) 2024-01-28 18:15:29 +08:00
Nelson Chan
2b8f55194f Fix: [JSON-Query] Prevent parsing string-only JSON (#4425) 2024-01-28 03:18:24 +08:00
Frank Elsinga
538f83205d chore/issue template modification for v2 (#4240)
Co-authored-by: Nelson Chan <3271800+chakflying@users.noreply.github.com>
2024-01-26 06:57:36 +08:00
Nelson Chan
cf075a8793 Fix: missing await in getRemoteBrowser() (#4418) 2024-01-26 06:53:15 +08:00
Nelson Chan
288cab6dd7 Fix: Make sure browser is connected before returning (#4417) 2024-01-25 07:59:42 +08:00
Philip Klostermann
95125cc417 [Ntfy] don't include url action with defaut URL value 2024-01-23 11:16:10 -05:00
Philip Klostermann
20b69acde2 [Ntfy] Only include action link if monitor url is defined #3274 2024-01-23 10:10:31 -05:00
AnnAngela
b4e45c7ce8 fix(notification-dingding): throw error when failed (#3598) 2024-01-20 03:29:13 +08:00
Louis Lam
36196f632d Translations Update from Weblate (#4386) 2024-01-18 03:48:14 +08:00
Paco Culebras
c31475e020 Translated using Weblate (Catalan)
Currently translated at 3.7% (33 of 885 strings)

Co-authored-by: Paco Culebras <pculebras@me.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ca/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:32:38 +08:00
kindercat
9e21c7cb02 Translated using Weblate (Romanian)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: kindercat <156439718+kindercat@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ro/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:32:38 +08:00
Nima Shayanfar
669fc02baa Translated using Weblate (Persian)
Currently translated at 96.8% (857 of 885 strings)

Co-authored-by: Nima Shayanfar <nsh20100@yahoo.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:32:38 +08:00
kindercat
371eb38198 Translated using Weblate (Romanian)
Currently translated at 87.2% (772 of 885 strings)

Co-authored-by: kindercat <156439718+kindercat@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ro/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:32:37 +08:00
Белич Дмитрий
64fe00f9f2 Translated using Weblate (Russian)
Currently translated at 100.0% (885 of 885 strings)

Co-authored-by: Белич Дмитрий <belicdima8@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:28:33 +08:00
Kisem
2fbdf4886e Translated using Weblate (Hungarian)
Currently translated at 84.5% (748 of 885 strings)

Co-authored-by: Kisem <kiss.m.aron@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:28:33 +08:00
ItzAndriss
5ebb160597 Translated using Weblate (Hungarian)
Currently translated at 84.5% (748 of 885 strings)

Co-authored-by: ItzAndriss <itzandriss@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:28:33 +08:00
Louis Lam
e47e3cf479 Translated using Weblate (Yue)
Currently translated at 11.8% (105 of 885 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:28:33 +08:00
kindercat
ef573d057b Translated using Weblate (Romanian)
Currently translated at 66.7% (590 of 884 strings)

Co-authored-by: kindercat <156439718+kindercat@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ro/
Translation: Uptime Kuma/Uptime Kuma
2024-01-18 03:28:32 +08:00
alejandro vasquez
2d64204ff1 Translated using Weblate (Spanish)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: alejandro vasquez <rootltsm@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Zandor Smith
2afd743a6d Translated using Weblate (Dutch)
Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (English)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Zandor Smith <info@zsinfo.nl>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
ITQ
08da5ad5d8 Translated using Weblate (Russian)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: ITQ <itq.dev@ya.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
JC
83c7b593da Translated using Weblate (Catalan)
Currently translated at 3.5% (31 of 884 strings)

Co-authored-by: JC <jjsuscc@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ca/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Adam Stachowicz
a2905b0686 Translated using Weblate (Polish)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Fabien BERNARD
7f4a23a5ac Translated using Weblate (French)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Fabien BERNARD <fabien.bernard@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Markus Fenes
465531ad98 Translated using Weblate (Norwegian Bokmål)
Currently translated at 61.3% (542 of 884 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 60.4% (534 of 884 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 54.9% (486 of 884 strings)

Co-authored-by: Markus Fenes <mafen@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nb_NO/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Itay-Asudi
f491879214 Translated using Weblate (Hebrew)
Currently translated at 0.3% (3 of 884 strings)

Co-authored-by: Itay-Asudi <itay.asudi@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/he/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Lê Huy Mạnh Tân
5ea712e826 Translated using Weblate (Vietnamese)
Currently translated at 56.2% (497 of 884 strings)

Co-authored-by: Lê Huy Mạnh Tân <tanmanh350@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/vi/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
dng-nguyn
423e66d609 Translated using Weblate (Vietnamese)
Currently translated at 56.2% (497 of 884 strings)

Co-authored-by: dng-nguyn <dungnguyen@dinhcap.dev>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/vi/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Elia Ronchetti
05f9f35cb3 Translated using Weblate (Italian)
Currently translated at 72.5% (641 of 884 strings)

Co-authored-by: Elia Ronchetti <e.ronchetti@campus.unimib.it>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Salvatore Cahyo
3b0800b78e Translated using Weblate (Indonesian)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Salvatore Cahyo <salvacmp18@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
renph
c33840fc9f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: renph <renph96@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Michal
44f8a8f8e9 Translated using Weblate (Czech)
Currently translated at 99.5% (881 of 885 strings)

Translated using Weblate (Czech)

Currently translated at 99.5% (880 of 884 strings)

Translated using Weblate (Czech)

Currently translated at 97.7% (864 of 884 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
AnnAngela
ca0385c449 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Abner Santana
ceb1d90095 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.8% (883 of 884 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Abner Santana <abnerss@outlook.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Jong Ryul Oh
b6a75e198c Translated using Weblate (Korean)
Currently translated at 84.6% (748 of 884 strings)

Co-authored-by: Jong Ryul Oh <hydromix@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:36 +00:00
Alanimdeo
999ed525e5 Translated using Weblate (Korean)
Currently translated at 84.6% (748 of 884 strings)

Co-authored-by: Alanimdeo <alan@imdeo.kr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
MrEddX
8773eed790 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Marco
f9b3f9766e Translated using Weblate (German)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (German)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (German)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
demonisius
eaa8939098 Translated using Weblate (Russian)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: demonisius <demonisius@mail.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Aji Priyo Wibowo
055aa8d2da Translated using Weblate (Indonesian)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Aji Priyo Wibowo <aji.wibowo@ionmobility.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Ivan Bratović
e815ee9192 Translated using Weblate (Croatian)
Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (Croatian)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Ivan Bratović <ivanbratovic4@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hr/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
stanol
3b7e3e093b Translated using Weblate (Ukrainian)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Thanassis Zografos
8cce068224 Translated using Weblate (Greek)
Currently translated at 76.0% (672 of 884 strings)

Co-authored-by: Thanassis Zografos <tzografos@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/el/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Ömer Faruk Genç
f8650239a6 Translated using Weblate (Turkish)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Rumplin
2a001d1aae Translated using Weblate (Slovenian)
Currently translated at 59.1% (523 of 884 strings)

Co-authored-by: Rumplin <rumplin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sl/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
leonsk29
0eca97f690 Translated using Weblate (Spanish)
Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: leonsk29 <leonsk29@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
ConfusedAlex
f296d8f533 Translated using Weblate (German)
Currently translated at 99.5% (880 of 884 strings)

Co-authored-by: ConfusedAlex <alex@epostnet.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Gunnar Norin
8150700906 Translated using Weblate (Swedish)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (Swedish)

Currently translated at 97.0% (858 of 884 strings)

Translated using Weblate (English)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Gunnar Norin <gunnar.norin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sv/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
Cyril59310
0ffa150c5d Translated using Weblate (French)
Currently translated at 100.0% (885 of 885 strings)

Translated using Weblate (French)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (French)

Currently translated at 100.0% (884 of 884 strings)

Translated using Weblate (French)

Currently translated at 100.0% (884 of 884 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2024-01-17 19:01:35 +00:00
James Cocker
8456912ae3 Corrected "Login" & "Logout" to verbs (EN) (#4320)
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2024-01-14 05:35:11 +08:00
Cyril59310
17e284f011 Missing translation key (#4363) 2024-01-14 04:59:13 +08:00
Louis Lam
d4c21a2259 [GitHub] Minor issue template wording 2024-01-09 01:35:10 +08:00
Frank Elsinga
7635ab54a0 made sure that the i18n does use navigator.languages instead of navigator.language for automatic language detection (#4244) 2024-01-07 23:55:10 +08:00
Louis Lam
f3dcdb6332 Update the demo server (#4296) 2024-01-07 23:24:28 +08:00
Adam Stachowicz
458cdf9f9b Fix encodeBase64 for empty password or user in HTTP Basic Authentication (#4326) 2024-01-07 02:06:06 +08:00
Louis Lam
9356e7dd4f Update clear stats (#4324) 2024-01-05 20:51:05 +08:00
Ben Scobie
25cb78796a Fix incorrect ping log (#4322) 2024-01-05 20:43:03 +08:00
Nelson Chan
bf1e3a3d5e Feat: Add stat_hourly & min. max. ping (#4267)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2024-01-05 20:42:24 +08:00
Louis Lam
0060e46b91 [README.md] Fix star badge 2024-01-04 03:13:31 +08:00
Abhishek Srinivasan
23e80882c6 Changed the color of delete button in dashboard from red to grey (#4307) 2024-01-04 00:29:38 +08:00
Louis Lam
5ebea3134a Merge 1.23.11 to master (#4306) 2024-01-03 03:04:12 +08:00
Louis Lam
2a315d4c84 Merge branch '1.23.X' into merge
# Conflicts:
#	package-lock.json
#	package.json
2024-01-03 02:10:01 +08:00
Louis Lam
f1e2ee74ea Update to 1.23.11 2023-12-31 05:46:54 +08:00
Louis Lam
8d847abf35 Update dependencies 2023-12-31 05:09:45 +08:00
Louis Lam
d7d57eafe3 Update Vue to 3.4 (#4300) 2023-12-30 23:13:21 +08:00
Louis Lam
329e2042bc Update to respect docker compose v2 (#4289) 2023-12-27 22:39:04 +08:00
Louis Lam
8151ac0e25 Fix Async child process output issue (#4231) 2023-12-14 04:54:34 +08:00
Thomas Spalinger
7f88aacbe7 make monitor start() and stop() async 2023-02-23 16:16:49 +00:00
Stefan Ottosson
f89ed0a3a4 feat: added HTTP method option for push monitor 2022-08-12 18:52:23 +02:00
192 changed files with 12107 additions and 4810 deletions

View File

@@ -1,7 +1,6 @@
/.idea
/node_modules
/data*
/cypress
/out
/test
/kubernetes

View File

@@ -1,7 +1,6 @@
module.exports = {
ignorePatterns: [
"test/*.js",
"test/cypress",
"server/modules/apicache/*",
"src/util.js"
],

View File

@@ -6,7 +6,7 @@ body:
- type: checkboxes
id: no-duplicate-issues
attributes:
label: "⚠️ Please verify that this bug has NOT been raised before."
label: "⚠️ Please verify that this question has NOT been raised before."
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)"
options:
- label: "I checked and didn't find similar issue"
@@ -24,7 +24,7 @@ body:
required: true
attributes:
label: "📝 Describe your problem"
description: "Please walk us through it step by step."
description: "Please walk us through it step by step. Include all important details and add screenshots where appropriate"
placeholder: "Describe what are you asking for..."
- type: textarea
id: error-msg
@@ -56,19 +56,20 @@ body:
placeholder: "Ex. Google Chrome 95.0.4638.69"
validations:
required: true
- type: input
id: docker-version
- type: textarea
id: deployment-info
attributes:
label: "🐋 Docker Version"
description: "If running with Docker, which version are you running?"
placeholder: "Ex. Docker 20.10.9 / K8S / Podman"
label: "🖥️ Deployment Environment"
description: |
examples:
- **Runtime**: Docker 20.10.9 / nodejs 14.18.0 / K8S via ... v1.3.3 / ..
- **Database**: sqlite/embedded mariadb/external mariadb
- **Filesystem used to store the database on**: Windows/ZFS/btrfs/NFSv3 on a SSD/HDD/eMMC
- **number of monitors**: 42
value: |
- Runtime:
- Database:
- Filesystem used to store the database on:
- number of monitors:
validations:
required: false
- type: input
id: nodejs-version
attributes:
label: "🟩 NodeJS Version"
description: "If running with Node.js? which version are you running?"
placeholder: "Ex. 14.18.0"
validations:
required: false
required: true

View File

@@ -3,14 +3,14 @@ description: "Submit a bug report to help us improve"
#title: "[Bug] "
labels: [bug]
body:
- type: checkboxes
id: no-duplicate-issues
- type: textarea
id: related-issues
validations:
required: true
attributes:
label: "⚠️ Please verify that this bug has NOT been raised before."
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)"
options:
- label: "I checked and didn't find similar issue"
required: true
label: "📑 I have found these related issues/pull requests"
description: "Search related issues by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=) and explain what the difference between them or explain that you are unable to find any related issues"
placeholder: "Related to #1 by also touching the ... system. They should not be merged because ..."
- type: checkboxes
attributes:
label: "🛡️ Security Policy"
@@ -31,7 +31,7 @@ body:
required: true
attributes:
label: "👟 Reproduction steps"
description: "How do you trigger this bug? Please walk us through it step by step."
description: "How do you trigger this bug? Please walk us through it step by step. Include all important details and add screenshots where appropriate"
placeholder: "..."
- type: textarea
id: expected-behavior
@@ -73,22 +73,23 @@ body:
placeholder: "Ex. Google Chrome 95.0.4638.69"
validations:
required: true
- type: input
id: docker-version
- type: textarea
id: deployment-info
attributes:
label: "🐋 Docker Version"
description: "If running with Docker, which version are you running?"
placeholder: "Ex. Docker 20.10.9 / K8S / Podman"
label: "🖥️ Deployment Environment"
description: |
examples:
- **Runtime**: Docker 20.10.9 / nodejs 18.17.1 / K8S via ... v1.3.3 / ..
- **Database**: sqlite/embedded mariadb/external mariadb
- **Filesystem used to store the database on**: Windows/ZFS/btrfs/NFSv3 on a SSD/HDD/eMMC
- **number of monitors**: 42
value: |
- Runtime:
- Database:
- Filesystem used to store the database on:
- number of monitors:
validations:
required: false
- type: input
id: nodejs-version
attributes:
label: "🟩 NodeJS Version"
description: "If running with Node.js? which version are you running?"
placeholder: "Ex. 14.18.0"
validations:
required: false
required: true
- type: textarea
id: logs
attributes:

View File

@@ -3,14 +3,14 @@ description: "Submit a proposal for a new feature"
#title: "[Feature] "
labels: [feature-request]
body:
- type: checkboxes
id: no-duplicate-issues
- type: textarea
id: related-issues
validations:
required: true
attributes:
label: "⚠️ Please verify that this feature request has NOT been suggested before."
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)"
options:
- label: "I checked and didn't find similar feature request"
required: true
label: "📑 I have found these related issues/pull requests"
description: "Search related issues by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=) and explain what the difference between them or explain that you are unable to find any related issues"
placeholder: "Related to #1 by also touching the ... system. They should not be merged because ..."
- type: dropdown
id: feature-area
attributes:
@@ -18,10 +18,17 @@ body:
description: "What kind of feature request is this?"
multiple: true
options:
- API
- New Notification
- New Monitor
- UI Feature
- API / automation options
- New notification-provider
- Change to existing notification-provider
- New monitor
- Change to existing monitor
- Dashboard
- Status-page
- Maintenance
- Deployment
- Certificate expiry
- Settings
- Other
validations:
required: true

View File

@@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest, ARM64]
node: [ 14, 20.5 ]
node: [ 18, 20.5 ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -33,7 +33,6 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm install npm@9 -g
- run: npm install
- run: npm run build
- run: npm run test-backend
@@ -46,11 +45,11 @@ jobs:
needs: [ check-linters ]
runs-on: ${{ matrix.os }}
timeout-minutes: 15
if: ${{ github.repository == 'louislam/uptime-kuma' }}
strategy:
matrix:
os: [ ARMv7 ]
node: [ 14, 20 ]
node: [ 18, 20 ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -61,7 +60,6 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm install npm@9 -g
- run: npm ci --production
check-linters:

View File

@@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node-version: [16]
node-version: [18]
steps:
- uses: actions/checkout@v4

25
.github/workflows/conflict_labeler.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Merge Conflict Labeler
on:
push:
branches:
- master
pull_request_target:
branches:
- master
types: [synchronize]
jobs:
label:
name: Labeling
runs-on: ubuntu-latest
if: ${{ github.repository == 'louislam/uptime-kuma' }}
permissions:
contents: read
pull-requests: write
steps:
- name: Apply label
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: 'needs:resolve-merge-conflict'
repoToken: '${{ secrets.GITHUB_TOKEN }}'

View File

@@ -11,12 +11,32 @@ jobs:
steps:
- uses: actions/stale@v8
with:
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.'
days-before-stale: 90
days-before-close: 2
stale-issue-message: |-
We are clearing up our old `help`-issues and your issue has been open for 60 days with no activity.
If no comment is made and the stale label is not removed, this issue will be closed in 7 days.
days-before-stale: 60
days-before-close: 7
days-before-pr-stale: -1
days-before-pr-close: -1
exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,feature-request'
exempt-issue-assignees: 'louislam'
operations-per-run: 200
- uses: actions/stale@v8
with:
stale-issue-message: |-
This issue was marked as `cannot-reproduce` by a maintainer.
If an issue is non-reproducible, we cannot fix it, as we do not know what the underlying issue is.
If you have any ideas how we can reproduce this issue, we would love to hear them.
We don't have a good way to deal with truely unreproducible issues and are going to close this issue in a month.
If think there might be other differences in our environment or in how we tried to reproduce this, we would appreciate any ideas.
close-issue-message: |-
This issue will be closed as no way to reproduce it has been found.
If you/somebody finds a way how to (semi-reliably) reproduce this, we can reopen this issue. ^^
days-before-stale: 180
days-before-close: 30
days-before-pr-stale: -1
days-before-pr-close: -1
any-of-issue-labels: 'cannot-reproduce'
operations-per-run: 200

View File

@@ -1,76 +1,193 @@
# Project Info
First of all, I want to thank everyone who have made pull requests for Uptime Kuma. I never thought the GitHub community would be so nice! Because of this, I also never thought that other people would actually read and edit my code. It is not very well structured or commented, sorry about that.
First of all, I want to thank everyone who have wrote issues or shared pull requests for Uptime Kuma.
I never thought the GitHub community would be so nice!
Because of this, I also never thought that other people would actually read and edit my code.
Parts of the code are not very well-structured or commented, sorry about that.
The project was created with vite.js (vue3). Then I created a subdirectory called "server" for the server part. Both frontend and backend share the same `package.json`.
The project was created with `vite.js` and is written in `vue3`.
Our backend lives in the `server`-directory and mostly communicates via websockets.
Both frontend and backend share the same `package.json`.
The frontend code builds into "dist" directory. The server (express.js) exposes the "dist" directory as the root of the endpoint. This is how production is working.
## Key Technical Skills
- Node.js (You should know about promises, async/await, arrow functions, etc.)
- Socket.io
- SCSS
- Vue.js
- Bootstrap
- SQLite
For production, the frontend is build into `dist`-directory and the server (`express.js`) exposes the `dist` directory as the root of the endpoint.
For development, we run vite in development mode on another port.
## Directories
- config (dev config files)
- data (App data)
- db (Base database and migration scripts)
- dist (Frontend build)
- docker (Dockerfiles)
- extra (Extra useful scripts)
- public (Frontend resources for dev only)
- server (Server source code)
- src (Frontend source code)
- test (unit test)
- `config` (dev config files)
- `data` (App data)
- `db` (Base database and migration scripts)
- `dist` (Frontend build)
- `docker` (Dockerfiles)
- `extra` (Extra useful scripts)
- `public` (Frontend resources for dev only)
- `server` (Server source code)
- `src` (Frontend source code)
- `test` (unit test)
## Can I create a pull request for Uptime Kuma?
Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**. Especially for a large pull request or you don't know if it will be merged or not.
Yes or no, it depends on what you will try to do.
Both your and our maintainers time is precious, and we don't want to waste both time.
Here are some references:
If you have any questions about any process/.. is not clear, you are likely not alone => please ask them ^^
### ✅ Usually accepted
Different guidelines exist for different types of pull requests (PRs):
- <details><summary><b>security fixes</b></summary>
<p>
Submitting security fixes is something that may put the community at risk.
Please read through our [security policy](SECURITY.md) and submit vulnerabilities via an [advisory](https://github.com/louislam/uptime-kuma/security/advisories/new) + [issue](https://github.com/louislam/uptime-kuma/issues/new?assignees=&labels=help&template=security.md) instead.
We encourage you to submit how to fix a vulnerability if you know how to, this is not required.
Following the security policy allows us to properly test, fix bugs.
This review allows us to notice, if there are any changes necessary to unrelated parts like the documentation.
[**PLEASE SEE OUR SECURITY POLICY.**](SECURITY.md)
</p>
</details>
- <details><summary><b>small, non-breaking bug fixes</b></summary>
<p>
If you come across a bug and think you can solve, we appreciate your work.
Please make sure that you follow by these rules:
- keep the PR as small as possible, fix only one thing at a time => keeping it reviewable
- test that your code does what you came it does.
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub>
</p>
</details>
- <details><summary><b>translations / internationalisation (i18n)</b></summary>
<p>
We use weblate to localise this project into many languages.
If you are unhappy with a translation this is the best start.
On how to translate using weblate, please see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
There are two cases in which a change cannot be done in weblate and requires a PR:
- A text may not be currently localisable. In this case, **adding a new language key** via `$t("languageKey")` might be nessesary
- language keys need to be **added to `en.json`** to be visible in weblate. If this has not happened, a PR is appreciated.
- **Adding a new language** requires a new file see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md)
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub>
</p>
</details>
- <details><summary><b>new notification providers</b></summary>
<p>
To set up a new notification provider these files need to be modified/created:
- `server/notification-providers/PROVIDER_NAME.js` is where the heart of the notification provider lives.
- Both `monitorJSON` and `heartbeatJSON` can be `null` for some events.
If both are `null`, this is a general testing message, but if just `heartbeatJSON` is `null` this is a certificate expiry.
- Please wrap the axios call into a
```js
try {
let result = await axios.post(...);
if (result.status === ...) ...
} catch (error) {
this.throwGeneralAxiosError(error);
}
```
- `server/notification.js` is where the backend of the notification provider needs to be registered.
*If you have an idea how we can skip this step, we would love to hear about it ^^*
- `src/components/NotificationDialog.vue` you need to decide if the provider is a regional or a global one and add it with a name to the respective list
- `src/components/notifications/PROVIDER_NAME.vue` is where the frontend of each provider lives.
Please make sure that you have:
- used `HiddenInput` for secret credentials
- included all the necessary helptexts/placeholder/.. to make sure the notification provider is simple to setup for new users.
- include all translations (`{{ $t("Translation key") }}`, [`i18n-t keypath="Translation key">`](https://vue-i18n.intlify.dev/guide/advanced/component.html)) in `src/lang/en.json` to enable our translators to translate this
- `src/components/notifications/index.js` is where the frontend of the provider needs to be registered.
*If you have an idea how we can skip this step, we would love to hear about it ^^*
- Bug fix
- Security fix
- Adding notification providers
- Adding new language files (see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md))
- Adding new language keys: `$t("...")`
Offering notifications is close to the core of what we are as an uptime monitor.
Therefore, making sure that they work is also really important.
Because testing notification providers is quite time intensive, we mostly offload this onto the person contributing a notification provider.
To make shure you have tested the notification provider, please include screenshots of the following events in the pull-request description:
- `UP`/`DOWN`
- Certificate Expiry via https://expired.badssl.com/
- Testing (the test button on the notification provider setup page)
Using the following way to format this is encouraged:
```md
| Event | Before | After |
------------------
| `UP` | paste-image-here | paste-image-here |
| `DOWN` | paste-image-here | paste-image-here |
| Certificate-expiry | paste-image-here | paste-image-here |
| Testing | paste-image-here | paste-image-here |
```
### ⚠️ Discussion required
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub>
</p>
</details>
- <details><summary><b>new monitoring types</b></summary>
<p>
- Large pull requests
- New features
To set up a new notification provider these files need to be modified/created:
- `server/monitor-types/MONITORING_TYPE.js` is the core of each monitor.
the `async check(...)`-function should:
- throw an error for each fault that is detected with an actionable error message
- in the happy-path, you should set `heartbeat.msg` to a successfull message and set `heartbeat.status = UP`
- `server/uptime-kuma-server.js` is where the monitoring backend needs to be registered.
*If you have an idea how we can skip this step, we would love to hear about it ^^*
- `src/pages/EditMonitor.vue` is the shared frontend users interact with.
Please make sure that you have:
- used `HiddenInput` for secret credentials
- included all the necessary helptexts/placeholder/.. to make sure the notification provider is simple to setup for new users.
- include all translations (`{{ $t("Translation key") }}`, [`i18n-t keypath="Translation key">`](https://vue-i18n.intlify.dev/guide/advanced/component.html)) in `src/lang/en.json` to enable our translators to translate this
-
### ❌ Won't be merged
- A dedicated PR for translating existing languages (see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md))
- Do not pass the auto-test
- Any breaking changes
- Duplicated pull requests
- Buggy
- UI/UX is not close to Uptime Kuma
- Modifications or deletions of existing logic without a valid reason.
- Adding functions that is completely out of scope
- Converting existing code into other programming languages
- Unnecessarily large code changes that are hard to review and cause conflicts with other PRs.
<sub>Because maintainer time is precious junior maintainers may merge uncontroversial PRs in this area.</sub>
</p>
</details>
- <details><summary><b>new features/ major changes / breaking bugfixes</b></summary>
<p>
be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**.
This is especially important for a large pull request or you don't know if it will be merged or not.
<sub>Because of the large impact of this work, only senior maintainers may merge PRs in this area.</sub>
</p>
</details>
The above cases may not cover all possible situations.
The following rules are essential for making your PR mergable:
- Merging multiple issues by a huge PR is more difficult to review and causes conflicts with other PRs. Please
- (if possible) **create one PR for one issue** or
- (if not possible) **explain which issues a PR addresses and why this PR should not be broken apart**
- Make sure your **PR passes our continuous integration**.
PRs will not be merged unless all CI-Checks are green.
- **Breaking changes** (unless for a good reason and discussed beforehand) will not get merged / not get merged quickly.
Such changes require a major version release.
- **Test your code** before submitting a PR.
Buggy PRs will not be merged.
- Make sure the **UI/UX is close to Uptime Kuma**.
- **Think about the maintainability**:
Don't add functionality that is completely **out of scope**.
Keep in mind that we need to be able to maintain the functionality.
- Don't modify or delete existing logic without a valid reason.
- Don't convert existing code into other programming languages for no reason.
I ([@louislam](https://github.com/louislam)) have the final say. If your pull request does not meet my expectations, I will reject it, no matter how much time you spent on it. Therefore, it is essential to have a discussion beforehand.
I ([@louislam](https://github.com/louislam)) have the final say.
If your pull request does not meet my expectations, I will reject it, no matter how much time you spent on it.
Therefore, it is essential to have a discussion beforehand.
I will assign your pull request to a [milestone](https://github.com/louislam/uptime-kuma/milestones), if I plan to review and merge it.
Also, please don't rush or ask for an ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests.
Please don't rush or ask for an ETA.
We have to understand the pull request, make sure it has no breaking changes and stick to the vision of this project, especially for large pull requests.
## I'd like to work on an issue. How do I do that?
We have found that assigning people to issues is management-overhead that we don't need.
A short comment that you want to try your hand at this issue is appreciated to save other devs time.
If you come across any problem during development, feel free to leave a comment with what you are stuck on.
### Recommended Pull Request Guideline
Before deep into coding, discussion first is preferred. Creating an empty pull request for discussion would be recommended.
Before diving deep into coding, having a discussion first by creating an empty pull request for discussion is preferred.
The rationale behind this is that we can align the direction and scope of the feature to eliminate any conflicts with existing and planned work, and can help by pointing out any potential pitfalls.
1. Fork the project
2. Clone your fork repo to local
@@ -84,10 +201,16 @@ Before deep into coding, discussion first is preferred. Creating an empty pull r
## Project Styles
I personally do not like something that requires so many configurations before you can finally start the app. I hope Uptime Kuma installation will be as easy as like installing a mobile app.
I personally do not like something that requires so many configurations before you can finally start the app.
The goal is to make the Uptime Kuma installation as easy as installing a mobile app.
- Easy to install for non-Docker users, no native build dependency is needed (for x86_64/armv7/arm64), no extra config, and no extra effort required to get it running
- Single container for Docker users, no very complex docker-compose file. Just map the volume and expose the port, then good to go
- Easy to install for non-Docker users
- no native build dependency is needed (for `x86_64`/`armv7`/`arm64`)
- no extra configuration and
- no extra effort required to get it running
- Single container for Docker users
- no complex docker-compose file
- mapping the volume and exposing the port should be the only requirements
- Settings should be configurable in the frontend. Environment variables are discouraged, unless it is related to startup such as `DATA_DIR`
- Easy to use
- The web UI styling should be consistent and nice
@@ -107,8 +230,8 @@ I personally do not like something that requires so many configurations before y
## Tools
- [`Node.js`](https://nodejs.org/) >= 14
- [`npm`](https://www.npmjs.com/) >= 8.5
- [`Node.js`](https://nodejs.org/) >= 18
- [`npm`](https://www.npmjs.com/) >= 9.3
- [`git`](https://git-scm.com/)
- IDE that supports [`ESLint`](https://eslint.org/) and EditorConfig (I am using [`IntelliJ IDEA`](https://www.jetbrains.com/idea/))
- A SQLite GUI tool (f.ex. [`SQLite Expert Personal`](https://www.sqliteexpert.com/download.html) or [`DBeaver Community`](https://dbeaver.io/download/))
@@ -154,25 +277,25 @@ npm run start-server-dev
It binds to `0.0.0.0:3001` by default.
It is mainly a socket.io app + express.js.
The backend is an `express.js` server with `socket.io` integrated.
It uses `socket.io` to communicate with clients, and most server logic is encapsulated in the `socket.io` handlers.
`express.js` is also used to serve:
express.js is used for:
- as an entry point for redirecting to a status page or the dashboard
- the frontend built files (`index.html`, `*.js`, `*.css`, etc.)
- internal APIs of the status page
- entry point such as redirecting to a status page or the dashboard
- serving the frontend built files (index.html, .js and .css etc.)
- serving internal APIs of the status page
### Structure in `/server/`
### Structure in /server/
- jobs/ (Jobs that are running in another process)
- model/ (Object model, auto-mapping to the database table name)
- modules/ (Modified 3rd-party modules)
- monitor_types (Monitor Types)
- notification-providers/ (individual notification logic)
- routers/ (Express Routers)
- socket-handler (Socket.io Handlers)
- server.js (Server entry point)
- uptime-kuma-server.js (UptimeKumaServer class, main logic should be here, but some still in `server.js`)
- `jobs/` (Jobs that are running in another process)
- `model/` (Object model, auto-mapping to the database table name)
- `modules/` (Modified 3rd-party modules)
- `monitor_types/` (Monitor Types)
- `notification-providers/` (individual notification logic)
- `routers/` (Express Routers)
- `socket-handler/` (Socket.io Handlers)
- `server.js` (Server entry point)
- `uptime-kuma-server.js` (UptimeKumaServer class, main logic should be here, but some still in `server.js`)
## Frontend Dev Server
@@ -211,14 +334,15 @@ npm test
## Dependencies
Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not used in the production environment, because it is usually also baked into dist files. So:
Both frontend and backend share the same `package.json`.
However, the frontend dependencies are eventually not used in the production environment, because it is usually also baked into `dist` files. So:
- Frontend dependencies = "devDependencies"
- Examples: vue, chart.js
- Examples: `vue`, `chart.js`
- Backend dependencies = "dependencies"
- Examples: socket.io, sqlite3
- Examples: `socket.io`, `sqlite3`
- Development dependencies = "devDependencies"
- Examples: eslint, sass
- Examples: `eslint`, `sass`
### Update Dependencies
@@ -289,54 +413,106 @@ https://github.com/louislam/uptime-kuma-wiki
Check the latest issues and pull requests:
https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc
### Release Procedures
### What is a maintainer and what are their roles?
1. Draft a release note
2. Make sure the repo is cleared
3. If the healthcheck is updated, remember to re-compile it: `npm run build-docker-builder-go`
4. `npm run release-final` with env vars: `VERSION` and `GITHUB_TOKEN`
5. Wait until the `Press any key to continue`
6. `git push`
7. Publish the release note as 1.X.X
8. Press any key to continue
9. Deploy to the demo server: `npm run deploy-demo-server`
This project has multiple maintainers which specialise in different areas.
Currently, there are 3 maintainers:
Checking:
| Person | Role | Main Area |
|-------------------|-------------------|------------------|
| `@louislam` | senior maintainer | major features |
| `@chakflying` | junior maintainer | fixing bugs |
| `@commanderstorm` | junior maintainer | issue-management |
- Check all tags is fine on https://hub.docker.com/r/louislam/uptime-kuma/tags
- Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / armv7)
- Try clean installation with Node.js
### Procedures
### Release Beta Procedures
We have a few procedures we follow. These are documented here:
- <details><summary>Set up a Docker Builder</summary>
<p>
1. Draft a release note, check "This is a pre-release"
2. Make sure the repo is cleared
3. `npm run release-beta` with env vars: `VERSION` and `GITHUB_TOKEN`
4. Wait until the `Press any key to continue`
5. Publish the release note as 1.X.X-beta.X
6. Press any key to continue
- amd64, armv7 using local.
- arm64 using remote arm64 cpu, as the emulator is too slow and can no longer pass the `npm ci` command.
1. Add the public key to the remote server.
2. Add the remote context. The remote machine must be arm64 and installed Docker CE.
```
docker context create oracle-arm64-jp --docker "host=ssh://root@100.107.174.88"
```
3. Create a new builder.
```
docker buildx create --name kuma-builder --platform linux/amd64,linux/arm/v7
docker buildx use kuma-builder
docker buildx inspect --bootstrap
```
4. Append the remote context to the builder.
```
docker buildx create --append --name kuma-builder --platform linux/arm64 oracle-arm64-jp
```
5. Verify the builder and check if the builder is using `kuma-builder`.
```
docker buildx inspect kuma-builder
docker buildx ls
```
</p>
</details>
- <details><summary>Release</summary>
<p>
### Release Wiki
1. Draft a release note
2. Make sure the repo is cleared
3. If the healthcheck is updated, remember to re-compile it: `npm run build-docker-builder-go`
4. `npm run release-final` with env vars: `VERSION` and `GITHUB_TOKEN`
5. Wait until the `Press any key to continue`
6. `git push`
7. Publish the release note as `1.X.X`
8. Press any key to continue
9. Deploy to the demo server: `npm run deploy-demo-server`
#### Setup Repo
These Items need to be checked:
```bash
git clone https://github.com/louislam/uptime-kuma-wiki.git
cd uptime-kuma-wiki
git remote add production https://github.com/louislam/uptime-kuma.wiki.git
```
- [ ] Check all tags is fine on https://hub.docker.com/r/louislam/uptime-kuma/tags
- [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / armv7)
- [ ] Try clean installation with Node.js
</p>
</details>
- <details><summary>Release Beta</summary>
<p>
#### Push to Production Wiki
1. Draft a release note, check `This is a pre-release`
2. Make sure the repo is cleared
3. `npm run release-beta` with env vars: `VERSION` and `GITHUB_TOKEN`
4. Wait until the `Press any key to continue`
5. Publish the release note as `1.X.X-beta.X`
6. Press any key to continue
</p>
</details>
- <details><summary>Release Wiki</summary>
<p>
```bash
git pull
git push production master
```
## Useful Commands
Change the base of a pull request such as `master` to `1.23.X`
```bash
git rebase --onto <new parent> <old parent>
```
**Setup Repo**
```bash
git clone https://github.com/louislam/uptime-kuma-wiki.git
cd uptime-kuma-wiki
git remote add production https://github.com/louislam/uptime-kuma.wiki.git
```
**Push to Production Wiki**
```bash
git pull
git push production master
```
</p>
</details>
- <details><summary>Change the base of a pull request such as <code>master</code> to <code>1.23.X</code></summary>
<p>
```bash
git rebase --onto <new parent> <old parent>
```
</p>
</details>

View File

@@ -6,7 +6,7 @@
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a>
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma?style=flat" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a>
[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam) <a href="https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/">
<img src="https://weblate.kuma.pet/widgets/uptime-kuma/-/svg-badge.svg" alt="Translation status" />
</a>
@@ -17,9 +17,9 @@ Uptime Kuma is an easy-to-use self-hosted monitoring tool.
Try it!
- Tokyo Demo Server: https://demo.uptime.kuma.pet (Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors))
Demo Server (Location: Frankfurt - Germany): https://demo.kuma.pet/start-demo
It is a temporary live demo, all data will be deleted after 10 minutes. Use the one that is closer to you, but I suggest that you should install and try it out for the best demo experience.
It is a temporary live demo, all data will be deleted after 10 minutes. Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors).
## ⭐ Features
@@ -43,11 +43,18 @@ It is a temporary live demo, all data will be deleted after 10 minutes. Use the
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
```
Uptime Kuma is now running on http://localhost:3001
Uptime Kuma is now running on <http://0.0.0.0:3001>.
> [!WARNING]
> File Systems like **NFS** (Network File System) are **NOT** supported. Please map to a local directory or volume.
> [!NOTE]
> If you want to limit exposure to localhost (without exposing port for other users or to use a [reverse proxy](https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy)), you can expose the port like this:
>
> ```bash
> docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
> ```
### 💪🏻 Non-Docker
Requirements:
@@ -56,15 +63,12 @@ Requirements:
- ✅ Major Linux distros such as Debian, Ubuntu, CentOS, Fedora and ArchLinux etc.
- ✅ Windows 10 (x64), Windows Server 2012 R2 (x64) or higher
- ❌ Replit / Heroku
- [Node.js](https://nodejs.org/en/download/) 14 / 16 / 18 / 20.4
- [Node.js](https://nodejs.org/en/download/) 18 / 20.4
- [npm](https://docs.npmjs.com/cli/) 9
- [Git](https://git-scm.com/downloads)
- [pm2](https://pm2.keymetrics.io/) - For running Uptime Kuma in the background
```bash
# Update your npm
npm install npm@9 -g
git clone https://github.com/louislam/uptime-kuma.git
cd uptime-kuma
npm run setup

9
compose.yaml Normal file
View File

@@ -0,0 +1,9 @@
services:
uptime-kuma:
image: louislam/uptime-kuma:1
volumes:
- ./data:/app/data
ports:
# <Host Port>:<Container Port>
- 3001:3001
restart: unless-stopped

View File

@@ -1,28 +0,0 @@
const { defineConfig } = require("cypress");
module.exports = defineConfig({
projectId: "vyjuem",
e2e: {
experimentalStudio: true,
setupNodeEvents(on, config) {
},
fixturesFolder: "test/cypress/fixtures",
screenshotsFolder: "test/cypress/screenshots",
videosFolder: "test/cypress/videos",
downloadsFolder: "test/cypress/downloads",
supportFile: "test/cypress/support/e2e.js",
baseUrl: "http://localhost:3002",
defaultCommandTimeout: 10000,
pageLoadTimeout: 60000,
viewportWidth: 1920,
viewportHeight: 1080,
specPattern: [
"test/cypress/e2e/setup.cy.js",
"test/cypress/e2e/**/*.js"
],
},
env: {
baseUrl: "http://localhost:3002",
},
});

View File

@@ -1,10 +0,0 @@
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
supportFile: false,
specPattern: [
"test/cypress/unit/**/*.js"
],
}
});

View File

@@ -2,6 +2,7 @@ import vue from "@vitejs/plugin-vue";
import { defineConfig } from "vite";
import visualizer from "rollup-plugin-visualizer";
import viteCompression from "vite-plugin-compression";
import VueDevTools from "vite-plugin-vue-devtools";
const postCssScss = require("postcss-scss");
const postcssRTLCSS = require("postcss-rtlcss");
@@ -32,6 +33,7 @@ export default defineConfig({
algorithm: "brotliCompress",
filter: viteCompressionFilter,
}),
VueDevTools(),
],
css: {
postcss: {

View File

@@ -318,7 +318,10 @@ async function createTables() {
// monitor_tls_info
await knex.schema.createTable("monitor_tls_info", (table) => {
table.increments("id");
table.integer("monitor_id").unsigned().notNullable(); //TODO: no fk ?
table.integer("monitor_id").unsigned().notNullable()
.references("id").inTable("monitor")
.onDelete("CASCADE")
.onUpdate("CASCADE");
table.text("info_json");
});

View File

@@ -0,0 +1,12 @@
exports.up = function (knex) {
return knex.schema
.alterTable("status_page", function (table) {
table.integer("auto_refresh_interval").defaultTo(300).unsigned();
});
};
exports.down = function (knex) {
return knex.schema.alterTable("status_page", function (table) {
table.dropColumn("auto_refresh_interval");
});
};

View File

@@ -0,0 +1,24 @@
exports.up = function (knex) {
return knex.schema
.alterTable("stat_daily", function (table) {
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
})
.alterTable("stat_minutely", function (table) {
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
});
};
exports.down = function (knex) {
return knex.schema
.alterTable("stat_daily", function (table) {
table.dropColumn("ping_min");
table.dropColumn("ping_max");
})
.alterTable("stat_minutely", function (table) {
table.dropColumn("ping_min");
table.dropColumn("ping_max");
});
};

View File

@@ -0,0 +1,26 @@
exports.up = function (knex) {
return knex.schema
.createTable("stat_hourly", function (table) {
table.increments("id");
table.comment("This table contains the hourly aggregate statistics for each monitor");
table.integer("monitor_id").unsigned().notNullable()
.references("id").inTable("monitor")
.onDelete("CASCADE")
.onUpdate("CASCADE");
table.integer("timestamp")
.notNullable()
.comment("Unix timestamp rounded down to the nearest hour");
table.float("ping").notNullable().comment("Average ping in milliseconds");
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
table.smallint("up").notNullable();
table.smallint("down").notNullable();
table.unique([ "monitor_id", "timestamp" ]);
});
};
exports.down = function (knex) {
return knex.schema
.dropTable("stat_hourly");
};

View File

@@ -0,0 +1,26 @@
exports.up = function (knex) {
return knex.schema
.alterTable("stat_daily", function (table) {
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
})
.alterTable("stat_minutely", function (table) {
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
})
.alterTable("stat_hourly", function (table) {
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
});
};
exports.down = function (knex) {
return knex.schema
.alterTable("stat_daily", function (table) {
table.dropColumn("extras");
})
.alterTable("stat_minutely", function (table) {
table.dropColumn("extras");
})
.alterTable("stat_hourly", function (table) {
table.dropColumn("extras");
});
};

View File

@@ -0,0 +1,18 @@
BEGIN TRANSACTION;
PRAGMA writable_schema = TRUE;
UPDATE
SQLITE_MASTER
SET
sql = replace(sql,
'monitor_id INTEGER NOT NULL',
'monitor_id INTEGER NOT NULL REFERENCES [monitor] ([id]) ON DELETE CASCADE ON UPDATE CASCADE'
)
WHERE
name = 'monitor_tls_info'
AND type = 'table';
PRAGMA writable_schema = RESET;
COMMIT;

View File

@@ -0,0 +1,18 @@
BEGIN TRANSACTION;
PRAGMA writable_schema = TRUE;
UPDATE
SQLITE_MASTER
SET
sql = replace(sql,
'monitor_id INTEGER NOT NULL',
'monitor_id INTEGER NOT NULL REFERENCES [monitor] ([id]) ON DELETE CASCADE ON UPDATE CASCADE'
)
WHERE
name = 'monitor_tls_info'
AND type = 'table';
PRAGMA writable_schema = RESET;
COMMIT;

View File

@@ -1,15 +0,0 @@
version: '3.8'
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
volumes:
- uptime-kuma:/app/data
ports:
- "3001:3001" # <Host Port>:<Container Port>
restart: always
volumes:
uptime-kuma:

View File

@@ -37,7 +37,7 @@ const github = require("@actions/github");
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please DO NOT open a blank issue.`
body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please **DO NOT open blank issues and use our [issue-templates](https://github.com/louislam/uptime-kuma/issues/new/choose) instead**.\nBlank Issues do not contain the context nessesary for a good discussions.`
});
// Close the issue

View File

@@ -8,6 +8,7 @@ const User = require("../server/model/user");
const { io } = require("socket.io-client");
const { localWebSocketURL } = require("../server/config");
const args = require("args-parser")(process.argv);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
@@ -19,10 +20,10 @@ const main = async () => {
}
console.log("Connecting the database");
Database.initDataDir(args);
await Database.connect(false, false, true);
try {
Database.initDataDir(args);
await Database.connect(false, false, true);
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
if (!process.env.TEST_BACKEND) {
const user = await R.findOne("user");

6909
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
"url": "https://github.com/louislam/uptime-kuma.git"
},
"engines": {
"node": "14 || 16 || 18 || >= 20.4.0"
"node": "18 || >= 20.4.0"
},
"scripts": {
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
@@ -49,7 +49,7 @@
"build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .",
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.23.10 && npm ci --production && npm run download-dist",
"setup": "git checkout 1.23.13 && npm ci --production && npm run download-dist",
"download-dist": "node extra/download-dist.js",
"mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js",
@@ -76,9 +76,9 @@
"dependencies": {
"@grpc/grpc-js": "~1.7.3",
"@louislam/ping": "~0.4.4-mod.1",
"@louislam/sqlite3": "15.1.6",
"@vvo/tzdb": "^6.125.0",
"args-parser": "~1.3.0",
"axios": "~0.27.0",
"axios": "~0.28.1",
"axios-ntlm": "1.3.0",
"badge-maker": "~3.3.1",
"bcryptjs": "~2.4.3",
@@ -92,7 +92,7 @@
"croner": "~6.0.5",
"dayjs": "~1.11.5",
"dotenv": "~16.0.3",
"express": "~4.17.3",
"express": "~4.19.2",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
"form-data": "~4.0.0",
@@ -116,11 +116,11 @@
"mongodb": "~4.17.1",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~3.6.2",
"mysql2": "~3.9.6",
"nanoid": "~3.3.4",
"node-cloudflared-tunnel": "~1.0.9",
"node-radius-client": "~1.0.0",
"nodemailer": "~6.6.5",
"nodemailer": "~6.9.13",
"nostr-tools": "^1.13.1",
"notp": "~2.0.3",
"openid-client": "^5.4.2",
@@ -139,14 +139,15 @@
"socket.io": "~4.6.1",
"socket.io-client": "~4.6.1",
"socks-proxy-agent": "6.1.1",
"tar": "~6.1.11",
"sqlite3": "~5.1.7",
"tar": "~6.2.1",
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3",
"ws": "^8.13.0"
},
"devDependencies": {
"@actions/github": "~5.0.1",
"@actions/github": "~5.1.1",
"@fortawesome/fontawesome-svg-core": "~1.2.36",
"@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4",
@@ -157,8 +158,8 @@
"@types/node": "^20.8.6",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@vitejs/plugin-vue": "~4.2.3",
"@vue/compiler-sfc": "~3.3.4",
"@vitejs/plugin-vue": "~5.0.1",
"@vue/compiler-sfc": "~3.4.2",
"@vuepic/vue-datepicker": "~3.4.8",
"aedes": "^0.46.3",
"bootstrap": "5.1.3",
@@ -170,7 +171,7 @@
"cross-env": "~7.0.3",
"delay": "^5.0.0",
"dns2": "~2.0.1",
"dompurify": "~2.4.3",
"dompurify": "~3.0.11",
"eslint": "~8.14.0",
"eslint-plugin-jsdoc": "~46.4.6",
"eslint-plugin-vue": "~8.7.1",
@@ -189,12 +190,12 @@
"stylelint-config-standard": "~25.0.0",
"terser": "~5.15.0",
"test": "~3.3.0",
"timezones-list": "~3.0.1",
"typescript": "~4.4.4",
"v-pagination-3": "~0.1.7",
"vite": "~4.4.1",
"vite": "~5.2.8",
"vite-plugin-compression": "^0.5.1",
"vue": "~3.3.4",
"vite-plugin-vue-devtools": "^7.0.15",
"vue": "~3.4.2",
"vue-chartjs": "~5.2.0",
"vue-confirm-dialog": "~1.0.2",
"vue-contenteditable": "~3.0.4",
@@ -203,7 +204,7 @@
"vue-multiselect": "~3.0.0-alpha.2",
"vue-prism-editor": "~2.0.0-alpha.2",
"vue-qrcode": "~1.0.0",
"vue-router": "~4.0.14",
"vue-router": "~4.2.5",
"vue-toastification": "~2.0.0-rc.5",
"vuedraggable": "~4.1.0",
"wait-on": "^7.2.0",

View File

@@ -130,7 +130,7 @@ function userAuthorizer(username, password, callback) {
* @param {express.Request} req Express request object
* @param {express.Response} res Express response object
* @param {express.NextFunction} next Next handler in chain
* @returns {void}
* @returns {Promise<void>}
*/
exports.basicAuth = async function (req, res, next) {
const middleware = basicAuth({
@@ -153,7 +153,7 @@ exports.basicAuth = async function (req, res, next) {
* @param {express.Request} req Express request object
* @param {express.Response} res Express response object
* @param {express.NextFunction} next Next handler in chain
* @returns {void}
* @returns {Promise<void>}
*/
exports.apiAuth = async function (req, res, next) {
if (!await Settings.get("disableAuth")) {

View File

@@ -8,6 +8,7 @@ const server = UptimeKumaServer.getInstance();
const io = server.io;
const { setting } = require("./util-server");
const checkVersion = require("./check-version");
const Database = require("./database");
/**
* Send list of notification providers to client
@@ -144,17 +145,20 @@ async function sendInfo(socket, hideVersion = false) {
let version;
let latestVersion;
let isContainer;
let dbType;
if (!hideVersion) {
version = checkVersion.version;
latestVersion = checkVersion.latestVersion;
isContainer = (process.env.UPTIME_KUMA_IS_CONTAINER === "1");
dbType = Database.dbConfig.type;
}
socket.emit("info", {
version,
latestVersion,
isContainer,
dbType,
primaryBaseURL: await setting("primaryBaseURL"),
serverTimezone: await server.getTimezone(),
serverTimezoneOffset: server.getTimezoneOffset(),

View File

@@ -105,7 +105,8 @@ class Database {
"patch-add-gamedig-given-port.sql": true,
"patch-notification-config.sql": true,
"patch-fix-kafka-producer-booleans.sql": true,
"patch-timeout.sql": true, // The last file so far converted to a knex migration file
"patch-timeout.sql": true,
"patch-monitor-tls-info-add-fk.sql": true, // The last file so far converted to a knex migration file
};
/**
@@ -208,9 +209,9 @@ class Database {
let config = {};
let mariadbPoolConfig = {
afterCreate: function (conn, done) {
}
min: 0,
max: 10,
idleTimeoutMillis: 30000,
};
log.info("db", `Database Type: ${dbConfig.type}`);
@@ -222,11 +223,8 @@ class Database {
fs.copyFileSync(Database.templatePath, Database.sqlitePath);
}
const Dialect = require("knex/lib/dialects/sqlite3/index.js");
Dialect.prototype._driver = () => require("@louislam/sqlite3");
config = {
client: Dialect,
client: "sqlite3",
connection: {
filename: Database.sqlitePath,
acquireConnectionTimeout: acquireConnectionTimeout,
@@ -378,7 +376,7 @@ class Database {
/**
* Patch the database
* @returns {void}
* @returns {Promise<void>}
*/
static async patch() {
// Still need to keep this for old versions of Uptime Kuma

View File

@@ -65,7 +65,7 @@ class DockerHost {
/**
* Fetches the amount of containers on the Docker host
* @param {object} dockerHost Docker host to check for
* @returns {number} Total amount of containers on the host
* @returns {Promise<number>} Total amount of containers on the host
*/
static async testDockerHost(dockerHost) {
const options = {

View File

@@ -9,7 +9,7 @@ class Group extends BeanModel {
* @param {boolean} showTags Should the JSON include monitor tags
* @param {boolean} certExpiry Should JSON include info about
* certificate expiry?
* @returns {object} Object ready to parse
* @returns {Promise<object>} Object ready to parse
*/
async toPublicJSON(showTags = false, certExpiry = false) {
let monitorBeanList = await this.getMonitorList();
@@ -29,7 +29,7 @@ class Group extends BeanModel {
/**
* Get all monitors
* @returns {Bean[]} List of monitors
* @returns {Promise<Bean[]>} List of monitors
*/
async getMonitorList() {
return R.convertToBeans("monitor", await R.getAll(`

View File

@@ -11,7 +11,7 @@ class Maintenance extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {object} Object ready to parse
* @returns {Promise<object>} Object ready to parse
*/
async toPublicJSON() {
@@ -98,7 +98,7 @@ class Maintenance extends BeanModel {
/**
* Return an object that ready to parse to JSON
* @param {string} timezone If not specified, the timeRange will be in UTC
* @returns {object} Object ready to parse
* @returns {Promise<object>} Object ready to parse
*/
async toJSON(timezone = null) {
return this.toPublicJSON(timezone);
@@ -143,7 +143,7 @@ class Maintenance extends BeanModel {
* Convert data from socket to bean
* @param {Bean} bean Bean to fill in
* @param {object} obj Data to fill bean with
* @returns {Bean} Filled bean
* @returns {Promise<Bean>} Filled bean
*/
static async jsonToBean(bean, obj) {
if (obj.id) {
@@ -189,9 +189,9 @@ class Maintenance extends BeanModel {
/**
* Throw error if cron is invalid
* @param {string|Date} cron Pattern or date
* @returns {Promise<void>}
* @returns {void}
*/
static async validateCron(cron) {
static validateCron(cron) {
let job = new Cron(cron, () => {});
job.stop();
}
@@ -324,7 +324,7 @@ class Maintenance extends BeanModel {
/**
* Is this maintenance currently active
* @returns {boolean} The maintenance is active?
* @returns {Promise<boolean>} The maintenance is active?
*/
async isUnderMaintenance() {
return (await this.getStatus()) === "under-maintenance";
@@ -332,7 +332,7 @@ class Maintenance extends BeanModel {
/**
* Get the timezone of the maintenance
* @returns {string} timezone
* @returns {Promise<string>} timezone
*/
async getTimezone() {
if (!this.timezone || this.timezone === "SAME_AS_SERVER") {
@@ -343,7 +343,7 @@ class Maintenance extends BeanModel {
/**
* Get offset for timezone
* @returns {string} offset
* @returns {Promise<string>} offset
*/
async getTimezoneOffset() {
return dayjs.tz(dayjs(), await this.getTimezone()).format("Z");
@@ -351,7 +351,7 @@ class Maintenance extends BeanModel {
/**
* Get the current status of the maintenance
* @returns {string} Current status
* @returns {Promise<string>} Current status
*/
async getStatus() {
if (!this.active) {

View File

@@ -4,8 +4,8 @@ const { Prometheus } = require("../prometheus");
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
SQL_DATETIME_FORMAT
} = require("../../src/util");
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery,
redisPingAsync, mongodbPing, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius,
redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
} = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
@@ -43,7 +43,7 @@ class Monitor extends BeanModel {
* @param {boolean} showTags Include tags in JSON
* @param {boolean} certExpiry Include certificate expiry info in
* JSON
* @returns {object} Object ready to parse
* @returns {Promise<object>} Object ready to parse
*/
async toPublicJSON(showTags = false, certExpiry = false) {
let obj = {
@@ -74,7 +74,7 @@ class Monitor extends BeanModel {
* Return an object that ready to parse to JSON
* @param {boolean} includeSensitiveData Include sensitive data in
* JSON
* @returns {object} Object ready to parse
* @returns {Promise<object>} Object ready to parse
*/
async toJSON(includeSensitiveData = true) {
@@ -96,11 +96,15 @@ class Monitor extends BeanModel {
screenshot = "/screenshots/" + jwt.sign(this.id, UptimeKumaServer.getInstance().jwtSecret) + ".png";
}
const path = await this.getPath();
const pathName = path.join(" / ");
let data = {
id: this.id,
name: this.name,
description: this.description,
pathName: await this.getPathName(),
path,
pathName,
parent: this.parent,
childrenIDs: await Monitor.getAllChildrenIDs(this.id),
url: this.url,
@@ -241,12 +245,12 @@ class Monitor extends BeanModel {
/**
* Encode user and password to Base64 encoding
* for HTTP "basic" auth, as per RFC-7617
* @param {string} user Username to encode
* @param {string} pass Password to encode
* @returns {string} Encoded username:password
* @param {string|null} user - The username (nullable if not changed by a user)
* @param {string|null} pass - The password (nullable if not changed by a user)
* @returns {string} Encoded Base64 string
*/
encodeBase64(user, pass) {
return Buffer.from(user + ":" + pass).toString("base64");
return Buffer.from(`${user || ""}:${pass || ""}`).toString("base64");
}
/**
@@ -324,9 +328,9 @@ class Monitor extends BeanModel {
/**
* Start monitor
* @param {Server} io Socket server instance
* @returns {void}
* @returns {Promise<void>}
*/
start(io) {
async start(io) {
let previousBeat = null;
let retries = 0;
@@ -529,6 +533,18 @@ class Monitor extends BeanModel {
}
}
let tlsInfo = {};
// Store tlsInfo when secureConnect event is emitted
// The keylog event listener is a workaround to access the tlsSocket
options.httpsAgent.once("keylog", async (line, tlsSocket) => {
tlsSocket.once("secureConnect", async () => {
tlsInfo = checkCertificate(tlsSocket);
tlsInfo.valid = tlsSocket.authorized || false;
await this.handleTlsInfo(tlsInfo);
});
});
log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`);
log.debug("monitor", `[${this.name}] Axios Request`);
@@ -538,31 +554,19 @@ class Monitor extends BeanModel {
bean.msg = `${res.status} - ${res.statusText}`;
bean.ping = dayjs().valueOf() - startTime;
// Check certificate if https is used
let certInfoStartTime = dayjs().valueOf();
if (this.getUrl()?.protocol === "https:") {
log.debug("monitor", `[${this.name}] Check cert`);
try {
let tlsInfoObject = checkCertificate(res);
tlsInfo = await this.updateTlsInfo(tlsInfoObject);
// fallback for if kelog event is not emitted, but we may still have tlsInfo,
// e.g. if the connection is made through a proxy
if (this.getUrl()?.protocol === "https:" && tlsInfo.valid === undefined) {
const tlsSocket = res.request.res.socket;
if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) {
log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`);
await this.checkCertExpiryNotifications(tlsInfoObject);
}
if (tlsSocket) {
tlsInfo = checkCertificate(tlsSocket);
tlsInfo.valid = tlsSocket.authorized || false;
} catch (e) {
if (e.message !== "No TLS certificate in response") {
log.error("monitor", "Caught error");
log.error("monitor", e.message);
}
await this.handleTlsInfo(tlsInfo);
}
}
if (process.env.TIMELOGGER === "1") {
log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
}
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID === this.id) {
log.info("monitor", res.data);
}
@@ -595,8 +599,12 @@ class Monitor extends BeanModel {
let data = res.data;
// convert data to object
if (typeof data === "string") {
data = JSON.parse(data);
if (typeof data === "string" && res.headers["content-type"] !== "application/json") {
try {
data = JSON.parse(data);
} catch (_) {
// Failed to parse as JSON, just process it as a string
}
}
let expression = jsonata(this.jsonPath);
@@ -765,37 +773,6 @@ class Monitor extends BeanModel {
bean.msg = "";
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "grpc-keyword") {
let startTime = dayjs().valueOf();
const options = {
grpcUrl: this.grpcUrl,
grpcProtobufData: this.grpcProtobuf,
grpcServiceName: this.grpcServiceName,
grpcEnableTls: this.grpcEnableTls,
grpcMethod: this.grpcMethod,
grpcBody: this.grpcBody,
};
const response = await grpcQuery(options);
bean.ping = dayjs().valueOf() - startTime;
log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`);
let responseData = response.data;
if (responseData.length > 50) {
responseData = responseData.toString().substring(0, 47) + "...";
}
if (response.code !== 1) {
bean.status = DOWN;
bean.msg = `Error in send gRPC ${response.code} ${response.errorMessage}`;
} else {
let keywordFound = response.data.toString().includes(this.keyword);
if (keywordFound === !this.isInvertKeyword()) {
bean.status = UP;
bean.msg = `${responseData}, keyword [${this.keyword}] ${keywordFound ? "is" : "not"} found`;
} else {
log.debug("monitor:", `GRPC response [${response.data}] + ", but keyword [${this.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${response.data} + "]"`);
bean.status = DOWN;
bean.msg = `, but keyword [${this.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${responseData} + "]`;
}
}
} else if (this.type === "postgres") {
let startTime = dayjs().valueOf();
@@ -814,15 +791,6 @@ class Monitor extends BeanModel {
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1", mysqlPassword);
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "mongodb") {
let startTime = dayjs().valueOf();
await mongodbPing(this.databaseConnectionString);
bean.msg = "";
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "radius") {
let startTime = dayjs().valueOf();
@@ -853,7 +821,7 @@ class Monitor extends BeanModel {
} else if (this.type === "redis") {
let startTime = dayjs().valueOf();
bean.msg = await redisPingAsync(this.databaseConnectionString);
bean.msg = await redisPingAsync(this.databaseConnectionString, !this.ignoreTls);
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
@@ -898,7 +866,6 @@ class Monitor extends BeanModel {
retries = 0;
} catch (error) {
if (error?.name === "CanceledError") {
bean.msg = `timeout by AbortSignal (${this.timeout}s)`;
} else {
@@ -943,7 +910,7 @@ class Monitor extends BeanModel {
log.debug("monitor", `[${this.name}] apicache clear`);
apicache.clear();
UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id);
await UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id);
} else {
bean.important = false;
@@ -971,6 +938,7 @@ class Monitor extends BeanModel {
} else if (bean.status === MAINTENANCE) {
log.warn("monitor", `Monitor #${this.id} '${this.name}': Under Maintenance | Type: ${this.type}`);
} else {
beatInterval = this.retryInterval;
log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type} | Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`);
}
@@ -1098,9 +1066,9 @@ class Monitor extends BeanModel {
/**
* Stop monitor
* @returns {void}
* @returns {Promise<void>}
*/
stop() {
async stop() {
clearTimeout(this.heartbeatInterval);
this.isStop = true;
@@ -1373,7 +1341,7 @@ class Monitor extends BeanModel {
let notifyDays = await setting("tlsExpiryNotifyDays");
if (notifyDays == null || !Array.isArray(notifyDays)) {
// Reset Default
setSetting("tlsExpiryNotifyDays", [ 7, 14, 21 ], "general");
await setSetting("tlsExpiryNotifyDays", [ 7, 14, 21 ], "general");
notifyDays = [ 7, 14, 21 ];
}
@@ -1527,11 +1495,11 @@ class Monitor extends BeanModel {
}
/**
* Gets Full Path-Name (Groups and Name)
* @returns {Promise<string>} Full path name of this monitor
* Gets the full path
* @returns {Promise<string[]>} Full path (includes groups and the name) of the monitor
*/
async getPathName() {
let path = this.name;
async getPath() {
const path = [ this.name ];
if (this.parent === null) {
return path;
@@ -1539,7 +1507,7 @@ class Monitor extends BeanModel {
let parent = await Monitor.getParent(this.id);
while (parent !== null) {
path = `${parent.name} / ${path}`;
path.unshift(parent.name);
parent = await Monitor.getParent(parent.id);
}
@@ -1569,7 +1537,7 @@ class Monitor extends BeanModel {
}
/**
* Unlinks all children of the the group monitor
* Unlinks all children of the group monitor
* @param {number} groupID ID of group to remove children of
* @returns {Promise<void>}
*/
@@ -1611,6 +1579,20 @@ class Monitor extends BeanModel {
return oAuthAccessToken;
}
/**
* Store TLS certificate information and check for expiry
* @param {object} tlsInfo Information about the TLS connection
* @returns {Promise<void>}
*/
async handleTlsInfo(tlsInfo) {
await this.updateTlsInfo(tlsInfo);
this.prometheus?.update(null, tlsInfo);
if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) {
log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`);
await this.checkCertExpiryNotifications(tlsInfo);
}
}
}
module.exports = Monitor;

View File

@@ -18,7 +18,7 @@ class StatusPage extends BeanModel {
* @param {Response} response Response object
* @param {string} indexHTML HTML to render
* @param {string} slug Status page slug
* @returns {void}
* @returns {Promise<void>}
*/
static async handleStatusPageResponse(response, indexHTML, slug) {
// Handle url with trailing slash (http://localhost:3001/status/)
@@ -42,7 +42,7 @@ class StatusPage extends BeanModel {
* SSR for status pages
* @param {string} indexHTML HTML page to render
* @param {StatusPage} statusPage Status page populate HTML with
* @returns {void}
* @returns {Promise<string>} the rendered html
*/
static async renderHTML(indexHTML, statusPage) {
const $ = cheerio.load(indexHTML);
@@ -238,6 +238,7 @@ class StatusPage extends BeanModel {
description: this.description,
icon: this.getIcon(),
theme: this.theme,
autoRefreshInterval: this.autoRefreshInterval,
published: !!this.published,
showTags: !!this.show_tags,
domainNameList: this.getDomainNameList(),
@@ -260,6 +261,7 @@ class StatusPage extends BeanModel {
title: this.title,
description: this.description,
icon: this.getIcon(),
autoRefreshInterval: this.autoRefreshInterval,
theme: this.theme,
published: !!this.published,
showTags: !!this.show_tags,

View File

@@ -0,0 +1,90 @@
const { MonitorType } = require("./monitor-type");
const { UP, log } = require("../../src/util");
const dayjs = require("dayjs");
const grpc = require("@grpc/grpc-js");
const protojs = require("protobufjs");
class GrpcKeywordMonitorType extends MonitorType {
name = "grpc-keyword";
/**
* @inheritdoc
*/
async check(monitor, heartbeat, _server) {
const startTime = dayjs().valueOf();
const service = this.constructGrpcService(this.grpcUrl, this.grpcProtobuf, this.grpcServiceName, this.grpcEnableTls);
let response = await this.grpcQuery(service, this.grpcMethod, this.grpcBody);
heartbeat.ping = dayjs().valueOf() - startTime;
log.debug(this.name, `gRPC response: ${response}`);
if (response.length > 50) {
response = response.toString().substring(0, 47) + "...";
}
let keywordFound = response.toString().includes(this.keyword);
if (keywordFound !== !this.isInvertKeyword()) {
log.debug(this.name, `GRPC response [${response}] + ", but keyword [${this.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${response} + "]"`);
throw new Error(`keyword [${this.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${response} + "]`);
}
heartbeat.status = UP;
heartbeat.msg = `${response}, keyword [${this.keyword}] ${keywordFound ? "is" : "not"} found`;
}
/**
* Create gRPC client
* @param {string} url grpc Url
* @param {string} protobufData grpc ProtobufData
* @param {string} serviceName grpc ServiceName
* @param {string} enableTls grpc EnableTls
* @returns {grpc.Service} grpc Service
*/
constructGrpcService(url, protobufData, serviceName, enableTls) {
const protocObject = protojs.parse(protobufData);
const protoServiceObject = protocObject.root.lookupService(serviceName);
const Client = grpc.makeGenericClientConstructor({});
const credentials = enableTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure();
const client = new Client(url, credentials);
return protoServiceObject.create((method, requestData, cb) => {
const fullServiceName = method.fullName;
const serviceFQDN = fullServiceName.split(".");
const serviceMethod = serviceFQDN.pop();
const serviceMethodClientImpl = `/${serviceFQDN.slice(1).join(".")}/${serviceMethod}`;
log.debug(this.name, `gRPC method ${serviceMethodClientImpl}`);
client.makeUnaryRequest(
serviceMethodClientImpl,
arg => arg,
arg => arg,
requestData,
cb);
}, false, false);
}
/**
* Create gRPC client stib
* @param {grpc.Service} service grpc Url
* @param {string} method grpc Method
* @param {string} body grpc Body
* @returns {Promise<string>} Result of gRPC query
*/
async grpcQuery(service, method, body) {
return new Promise((resolve, reject) => {
try {
service[`${method}`](JSON.parse(body), (err, response) => {
if (err) {
if (err.code !== 1) {
reject(`Error in send gRPC ${err.code} ${err.details}`);
}
log.debug(this.name, `ignoring ${err.code} ${err.details}, as code=1 is considered OK`);
resolve(`${err.code} is considered OK because ${err.details}`);
}
resolve(JSON.stringify(response));
});
} catch (err) {
reject(`Error ${err}. Please review your gRPC configuration option. The service name must not include package name value, and the method name must follow camelCase format`);
}
});
}
}
module.exports = {
GrpcKeywordMonitorType,
};

View File

@@ -0,0 +1,65 @@
const { MonitorType } = require("./monitor-type");
const { UP } = require("../../src/util");
const { MongoClient } = require("mongodb");
const jsonata = require("jsonata");
class MongodbMonitorType extends MonitorType {
name = "mongodb";
/**
* @inheritdoc
*/
async check(monitor, heartbeat, _server) {
let command = { "ping": 1 };
if (monitor.databaseQuery) {
command = JSON.parse(monitor.databaseQuery);
}
let result = await this.runMongodbCommand(monitor.databaseConnectionString, command);
if (result["ok"] !== 1) {
throw new Error("MongoDB command failed");
} else {
heartbeat.msg = "Command executed successfully";
}
if (monitor.jsonPath) {
let expression = jsonata(monitor.jsonPath);
result = await expression.evaluate(result);
if (result) {
heartbeat.msg = "Command executed successfully and the jsonata expression produces a result.";
} else {
throw new Error("Queried value not found.");
}
}
if (monitor.expectedValue) {
if (result.toString() === monitor.expectedValue) {
heartbeat.msg = "Command executed successfully and expected value was found";
} else {
throw new Error("Query executed, but value is not equal to expected value, value was: [" + JSON.stringify(result) + "]");
}
}
heartbeat.status = UP;
}
/**
* Connect to and run MongoDB command on a MongoDB database
* @param {string} connectionString The database connection string
* @param {object} command MongoDB command to run on the database
* @returns {Promise<(string[] | object[] | object)>} Response from
* server
*/
async runMongodbCommand(connectionString, command) {
let client = await MongoClient.connect(connectionString);
let result = await client.db().command(command);
await client.close();
return result;
}
}
module.exports = {
MongodbMonitorType,
};

View File

@@ -1,5 +1,4 @@
class MonitorType {
name = undefined;
/**

View File

@@ -81,7 +81,8 @@ class MqttMonitorType extends MonitorType {
let client = mqtt.connect(mqttUrl, {
username,
password
password,
clientId: "uptime-kuma_" + Math.random().toString(16).substr(2, 8)
});
client.on("connect", () => {

View File

@@ -10,6 +10,10 @@ const jwt = require("jsonwebtoken");
const config = require("../config");
const { RemoteBrowser } = require("../remote-browser");
/**
* Cached instance of a browser
* @type {import ("playwright-core").Browser}
*/
let browser = null;
let allowedList = [];
@@ -71,10 +75,12 @@ async function isAllowedChromeExecutable(executablePath) {
/**
* Get the current instance of the browser. If there isn't one, create
* it.
* @returns {Promise<Browser>} The browser
* @returns {Promise<import ("playwright-core").Browser>} The browser
*/
async function getBrowser() {
if (!browser) {
if (browser && browser.isConnected()) {
return browser;
} else {
let executablePath = await Settings.get("chromeExecutable");
executablePath = await prepareChromeExecutable(executablePath);
@@ -83,8 +89,9 @@ async function getBrowser() {
//headless: false,
executablePath,
});
return browser;
}
return browser;
}
/**
@@ -96,7 +103,7 @@ async function getBrowser() {
async function getRemoteBrowser(remoteBrowserID, userId) {
let remoteBrowser = await RemoteBrowser.get(remoteBrowserID, userId);
log.debug("MONITOR", `Using remote browser: ${remoteBrowser.name} (${remoteBrowser.id})`);
browser = chromium.connect(remoteBrowser.url);
browser = await chromium.connect(remoteBrowser.url);
return browser;
}

View File

@@ -16,7 +16,7 @@ class TailscalePing extends MonitorType {
* @param {object} monitor The monitor object associated with the check.
* @param {object} heartbeat The heartbeat object to update.
* @returns {Promise<void>}
* @throws Will throw an error if checking Tailscale ping encounters any error
* @throws Error if checking Tailscale ping encounters any error
*/
async check(monitor, heartbeat) {
try {
@@ -38,7 +38,8 @@ class TailscalePing extends MonitorType {
async runTailscalePing(hostname, interval) {
let timeout = interval * 1000 * 0.8;
let res = await childProcessAsync.spawn("tailscale", [ "ping", "--c", "1", hostname ], {
timeout: timeout
timeout: timeout,
encoding: "utf8",
});
if (res.stderr && res.stderr.toString()) {
throw new Error(`Error in output: ${res.stderr.toString()}`);

View File

@@ -3,17 +3,15 @@ const { DOWN, UP } = require("../../src/util");
const axios = require("axios");
class Alerta extends NotificationProvider {
name = "alerta";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let alertaUrl = `${notification.alertaApiEndpoint}`;
let config = {
headers: {
"Content-Type": "application/json;charset=UTF-8",
@@ -40,7 +38,7 @@ class Alerta extends NotificationProvider {
resource: "Message",
}, data);
await axios.post(alertaUrl, postData, config);
await axios.post(notification.alertaApiEndpoint, postData, config);
} else {
let datadup = Object.assign( {
correlate: [ "service_up", "service_down" ],
@@ -52,11 +50,11 @@ class Alerta extends NotificationProvider {
if (heartbeatJSON["status"] === DOWN) {
datadup.severity = notification.alertaAlertState; // critical
datadup.text = "Service " + monitorJSON["type"] + " is down.";
await axios.post(alertaUrl, datadup, config);
await axios.post(notification.alertaApiEndpoint, datadup, config);
} else if (heartbeatJSON["status"] === UP) {
datadup.severity = notification.alertaRecoverState; // cleaned
datadup.text = "Service " + monitorJSON["type"] + " is up.";
await axios.post(alertaUrl, datadup, config);
await axios.post(notification.alertaApiEndpoint, datadup, config);
}
}
return okMsg;

View File

@@ -4,14 +4,14 @@ const { setting } = require("../util-server");
const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util");
class AlertNow extends NotificationProvider {
name = "AlertNow";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let textMsg = "";
let status = "open";

View File

@@ -11,7 +11,7 @@ class AliyunSMS extends NotificationProvider {
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
if (heartbeatJSON != null) {
@@ -44,7 +44,7 @@ class AliyunSMS extends NotificationProvider {
* Send the SMS notification
* @param {BeanModel} notification Notification details
* @param {string} msgbody Message template
* @returns {boolean} True if successful else false
* @returns {Promise<boolean>} True if successful else false
*/
async sendSms(notification, msgbody) {
let params = {

View File

@@ -2,26 +2,29 @@ const NotificationProvider = require("./notification-provider");
const childProcessAsync = require("promisify-child-process");
class Apprise extends NotificationProvider {
name = "apprise";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const args = [ "-vv", "-b", msg, notification.appriseURL ];
if (notification.title) {
args.push("-t");
args.push(notification.title);
}
const s = await childProcessAsync.spawn("apprise", args);
const s = await childProcessAsync.spawn("apprise", args, {
encoding: "utf8",
});
const output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
if (output) {
if (! output.includes("ERROR")) {
return "Sent Successfully";
return okMsg;
}
throw new Error(output);

View File

@@ -46,29 +46,29 @@ class Bark extends NotificationProvider {
}
/**
* Add additional parameter for Bark v1 endpoints
* Add additional parameter for Bark v1 endpoints.
* Leads to better on device styles (iOS 15 optimized)
* @param {BeanModel} notification Notification to send
* @param {string} postUrl URL to append parameters to
* @returns {string} Additional URL parameters
*/
appendAdditionalParameters(notification, postUrl) {
additionalParameters(notification) {
// set icon to uptime kuma icon, 11kb should be fine
postUrl += "?icon=" + barkNotificationAvatar;
let params = "?icon=" + barkNotificationAvatar;
// grouping all our notifications
if (notification.barkGroup != null) {
postUrl += "&group=" + notification.barkGroup;
params += "&group=" + notification.barkGroup;
} else {
// default name
postUrl += "&group=" + "UptimeKuma";
params += "&group=" + "UptimeKuma";
}
// picked a sound, this should follow system's mute status when arrival
if (notification.barkSound != null) {
postUrl += "&sound=" + notification.barkSound;
params += "&sound=" + notification.barkSound;
} else {
// default sound
postUrl += "&sound=" + "telegraph";
params += "&sound=" + "telegraph";
}
return postUrl;
return params;
}
/**
@@ -92,7 +92,7 @@ class Bark extends NotificationProvider {
* @param {string} title Message title
* @param {string} subtitle Message
* @param {string} endpoint Endpoint to send request to
* @returns {string} Success message
* @returns {Promise<string>} Success message
*/
async postNotification(notification, title, subtitle, endpoint) {
let result;
@@ -100,9 +100,8 @@ class Bark extends NotificationProvider {
// url encode title and subtitle
title = encodeURIComponent(title);
subtitle = encodeURIComponent(subtitle);
let postUrl = endpoint + "/" + title + "/" + subtitle;
postUrl = this.appendAdditionalParameters(notification, postUrl);
result = await axios.get(postUrl);
const params = this.additionalParameters(notification);
result = await axios.get(`${endpoint}/${title}/${subtitle}${params}`);
} else {
result = await axios.post(`${endpoint}/push`, {
title,

View File

@@ -0,0 +1,31 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { UP } = require("../../src/util");
class Bitrix24 extends NotificationProvider {
name = "Bitrix24";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
try {
const params = {
user_id: notification.bitrix24UserID,
message: "[B]Uptime Kuma[/B]",
"ATTACH[COLOR]": (heartbeatJSON ?? {})["status"] === UP ? "#b73419" : "#67b518",
"ATTACH[BLOCKS][0][MESSAGE]": msg
};
await axios.get(`${notification.bitrix24WebhookURL}/im.notify.system.add.json`, { params });
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Bitrix24;

View File

@@ -0,0 +1,23 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class CallMeBot extends NotificationProvider {
name = "CallMeBot";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
try {
const url = new URL(notification.callMeBotEndpoint);
url.searchParams.set("text", msg);
await axios.get(url.toString());
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = CallMeBot;

View File

@@ -0,0 +1,39 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Cellsynt extends NotificationProvider {
name = "Cellsynt";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const data = {
// docs at https://www.cellsynt.com/en/sms/api-integration
params: {
"username": notification.cellsyntLogin,
"password": notification.cellsyntPassword,
"destination": notification.cellsyntDestination,
"text": msg.replace(/[^\x00-\x7F]/g, ""),
"originatortype": notification.cellsyntOriginatortype,
"originator": notification.cellsyntOriginator,
"allowconcat": notification.cellsyntAllowLongSMS ? 6 : 1
}
};
try {
const resp = await axios.post("https://se-1.cellsynt.net/sms.php", null, data);
if (resp.data == null ) {
throw new Error("Could not connect to Cellsynt, please try again.");
} else if (resp.data.includes("Error:")) {
resp.data = resp.data.replaceAll("Error:", "");
throw new Error(resp.data);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Cellsynt;

View File

@@ -2,14 +2,15 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class ClickSendSMS extends NotificationProvider {
name = "clicksendsms";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://rest.clicksend.com/v3/sms/send";
try {
let config = {
headers: {
@@ -28,7 +29,7 @@ class ClickSendSMS extends NotificationProvider {
}
]
};
let resp = await axios.post("https://rest.clicksend.com/v3/sms/send", data, config);
let resp = await axios.post(url, data, config);
if (resp.data.data.messages[0].status !== "SUCCESS") {
let error = "Something gone wrong. Api returned " + resp.data.data.messages[0].status + ".";
this.throwGeneralAxiosError(error);

View File

@@ -10,7 +10,7 @@ class DingDing extends NotificationProvider {
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
if (heartbeatJSON != null) {
@@ -19,9 +19,12 @@ class DingDing extends NotificationProvider {
markdown: {
title: `[${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]}`,
text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]} \n> ${heartbeatJSON["msg"]}\n> Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
},
"at": {
"isAtAll": notification.mentioning === "everyone"
}
};
if (this.sendToDingDing(notification, params)) {
if (await this.sendToDingDing(notification, params)) {
return okMsg;
}
} else {
@@ -31,7 +34,7 @@ class DingDing extends NotificationProvider {
content: msg
}
};
if (this.sendToDingDing(notification, params)) {
if (await this.sendToDingDing(notification, params)) {
return okMsg;
}
}
@@ -44,7 +47,7 @@ class DingDing extends NotificationProvider {
* Send message to DingDing
* @param {BeanModel} notification Notification to send
* @param {object} params Parameters of message
* @returns {boolean} True if successful else false
* @returns {Promise<boolean>} True if successful else false
*/
async sendToDingDing(notification, params) {
let timestamp = Date.now();
@@ -62,7 +65,7 @@ class DingDing extends NotificationProvider {
if (result.data.errmsg === "ok") {
return true;
}
return false;
throw new Error(result.data.errmsg);
}
/**

View File

@@ -3,17 +3,20 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class Discord extends NotificationProvider {
name = "discord";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
const discordDisplayName = notification.discordUsername || "Uptime Kuma";
const webhookUrl = new URL(notification.discordWebhookUrl);
if (notification.discordChannelType === "postToThread") {
webhookUrl.searchParams.append("thread_id", notification.threadId);
}
// If heartbeatJSON is null, assume we're testing.
if (heartbeatJSON == null) {
@@ -21,7 +24,12 @@ class Discord extends NotificationProvider {
username: discordDisplayName,
content: msg,
};
await axios.post(notification.discordWebhookUrl, discordtestdata);
if (notification.discordChannelType === "createNewForumPost") {
discordtestdata.thread_name = notification.postName;
}
await axios.post(webhookUrl.toString(), discordtestdata);
return okMsg;
}
@@ -73,12 +81,14 @@ class Discord extends NotificationProvider {
],
}],
};
if (notification.discordChannelType === "createNewForumPost") {
discorddowndata.thread_name = notification.postName;
}
if (notification.discordPrefixMessage) {
discorddowndata.content = notification.discordPrefixMessage;
}
await axios.post(notification.discordWebhookUrl, discorddowndata);
await axios.post(webhookUrl.toString(), discorddowndata);
return okMsg;
} else if (heartbeatJSON["status"] === UP) {
@@ -109,11 +119,15 @@ class Discord extends NotificationProvider {
}],
};
if (notification.discordChannelType === "createNewForumPost") {
discordupdata.thread_name = notification.postName;
}
if (notification.discordPrefixMessage) {
discordupdata.content = notification.discordPrefixMessage;
}
await axios.post(notification.discordWebhookUrl, discordupdata);
await axios.post(webhookUrl.toString(), discordupdata);
return okMsg;
}
} catch (error) {

View File

@@ -9,8 +9,7 @@ class Feishu extends NotificationProvider {
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let feishuWebHookUrl = notification.feishuWebHookUrl;
const okMsg = "Sent Successfully.";
try {
if (heartbeatJSON == null) {
@@ -20,59 +19,67 @@ class Feishu extends NotificationProvider {
text: msg,
},
};
await axios.post(feishuWebHookUrl, testdata);
await axios.post(notification.feishuWebHookUrl, testdata);
return okMsg;
}
if (heartbeatJSON["status"] === DOWN) {
let downdata = {
msg_type: "post",
content: {
post: {
zh_cn: {
title: "UptimeKuma Alert: [Down] " + monitorJSON["name"],
content: [
[
{
tag: "text",
text:
"[Down] " +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
},
],
],
},
msg_type: "interactive",
card: {
config: {
update_multi: false,
wide_screen_mode: true,
},
},
header: {
title: {
tag: "plain_text",
content: "UptimeKuma Alert: [Down] " + monitorJSON["name"],
},
template: "red",
},
elements: [
{
tag: "div",
text: {
tag: "lark_md",
content: getContent(heartbeatJSON),
},
}
]
}
};
await axios.post(feishuWebHookUrl, downdata);
await axios.post(notification.feishuWebHookUrl, downdata);
return okMsg;
}
if (heartbeatJSON["status"] === UP) {
let updata = {
msg_type: "post",
content: {
post: {
zh_cn: {
title: "UptimeKuma Alert: [Up] " + monitorJSON["name"],
content: [
[
{
tag: "text",
text:
"[Up] " +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
},
],
],
},
msg_type: "interactive",
card: {
config: {
update_multi: false,
wide_screen_mode: true,
},
},
header: {
title: {
tag: "plain_text",
content: "UptimeKuma Alert: [UP] " + monitorJSON["name"],
},
template: "green",
},
elements: [
{
tag: "div",
text: {
tag: "lark_md",
content: getContent(heartbeatJSON),
},
},
]
}
};
await axios.post(feishuWebHookUrl, updata);
await axios.post(notification.feishuWebHookUrl, updata);
return okMsg;
}
} catch (error) {
@@ -81,4 +88,17 @@ class Feishu extends NotificationProvider {
}
}
/**
* Get content
* @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
* @returns {string} Return Successful Message
*/
function getContent(heartbeatJSON) {
return [
"**Message**: " + heartbeatJSON["msg"],
"**Ping**: " + (heartbeatJSON["ping"] == null ? "N/A" : heartbeatJSON["ping"] + " ms"),
`**Time (${heartbeatJSON["timezone"]})**: ${heartbeatJSON["localDateTime"]}`
].join("\n");
}
module.exports = Feishu;

View File

@@ -62,6 +62,15 @@ class FlashDuty extends NotificationProvider {
* @returns {string} Success message
*/
async postNotification(notification, title, body, monitorInfo, eventStatus) {
let labels = {
resource: this.genMonitorUrl(monitorInfo),
check: monitorInfo.name,
};
if (monitorInfo.tags && monitorInfo.tags.length > 0) {
for (let tag of monitorInfo.tags) {
labels[tag.name] = tag.value;
}
}
const options = {
method: "POST",
url: "https://api.flashcat.cloud/event/push/alert/standard?integration_key=" + notification.flashdutyIntegrationKey,
@@ -71,9 +80,7 @@ class FlashDuty extends NotificationProvider {
title,
event_status: eventStatus || "Info",
alert_key: String(monitorInfo.id) || Math.random().toString(36).substring(7),
labels: monitorInfo?.tags?.reduce((acc, item) => ({ ...acc,
[item.name]: item.value
}), { resource: this.genMonitorUrl(monitorInfo) }),
labels,
}
};

View File

@@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class FreeMobile extends NotificationProvider {
name = "FreeMobile";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
await axios.post(`https://smsapi.free-mobile.fr/sendmsg?msg=${encodeURIComponent(msg.replace("🔴", "⛔️"))}`, {
"user": notification.freemobileUser,

View File

@@ -3,21 +3,20 @@ const axios = require("axios");
const { UP } = require("../../src/util");
class GoAlert extends NotificationProvider {
name = "GoAlert";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let closeAction = "close";
let data = {
summary: msg,
};
if (heartbeatJSON != null && heartbeatJSON["status"] === UP) {
data["action"] = closeAction;
data["action"] = "close";
}
let headers = {
"Content-Type": "multipart/form-data",
@@ -27,7 +26,6 @@ class GoAlert extends NotificationProvider {
};
await axios.post(`${notification.goAlertBaseURL}/api/v2/generic/incoming?token=${notification.goAlertToken}`, data, config);
return okMsg;
} catch (error) {
let msg = (error.response.data) ? error.response.data : "Error without response";
throw new Error(msg);

View File

@@ -1,41 +1,85 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { setting } = require("../util-server");
const { getMonitorRelativeURL } = require("../../src/util");
const { DOWN, UP } = require("../../src/util");
const { getMonitorRelativeURL, UP } = require("../../src/util");
class GoogleChat extends NotificationProvider {
name = "GoogleChat";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
// Google Chat message formatting: https://developers.google.com/chat/api/guides/message-formats/basic
let textMsg = "";
if (heartbeatJSON && heartbeatJSON.status === UP) {
textMsg = "✅ Application is back online\n";
} else if (heartbeatJSON && heartbeatJSON.status === DOWN) {
textMsg = "🔴 Application went down\n";
let chatHeader = {
title: "Uptime Kuma Alert",
};
if (monitorJSON && heartbeatJSON) {
chatHeader["title"] =
heartbeatJSON["status"] === UP
? `${monitorJSON["name"]} is back online`
: `🔴 ${monitorJSON["name"]} went down`;
}
if (monitorJSON && monitorJSON.name) {
textMsg += `*${monitorJSON.name}*\n`;
// always show msg
let sectionWidgets = [
{
textParagraph: {
text: `<b>Message:</b>\n${msg}`,
},
},
];
// add time if available
if (heartbeatJSON) {
sectionWidgets.push({
textParagraph: {
text: `<b>Time (${heartbeatJSON["timezone"]}):</b>\n${heartbeatJSON["localDateTime"]}`,
},
});
}
textMsg += `${msg}`;
// add button for monitor link if available
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorJSON) {
textMsg += `\n${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
if (baseURL) {
const urlPath = monitorJSON ? getMonitorRelativeURL(monitorJSON.id) : "/";
sectionWidgets.push({
buttonList: {
buttons: [
{
text: "Visit Uptime Kuma",
onClick: {
openLink: {
url: baseURL + urlPath,
},
},
},
],
},
});
}
const data = {
"text": textMsg,
let chatSections = [
{
widgets: sectionWidgets,
},
];
// construct json data
let data = {
cardsV2: [
{
card: {
header: chatHeader,
sections: chatSections,
},
},
],
};
await axios.post(notification.googleChatWebhookURL, data);

View File

@@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Gorush extends NotificationProvider {
name = "gorush";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
let platformMapping = {
"ios": 1,

View File

@@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Gotify extends NotificationProvider {
name = "gotify";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) {
notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1);

View File

@@ -3,19 +3,18 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class GrafanaOncall extends NotificationProvider {
name = "GrafanaOncall";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
if (!notification.GrafanaOncallURL) {
throw new Error("GrafanaOncallURL cannot be empty");
}
let okMsg = "Sent Successfully.";
try {
if (heartbeatJSON === null) {
let grafanaupdata = {
@@ -23,10 +22,7 @@ class GrafanaOncall extends NotificationProvider {
message: msg,
state: "alerting",
};
await axios.post(
notification.GrafanaOncallURL,
grafanaupdata
);
await axios.post(notification.GrafanaOncallURL, grafanaupdata);
return okMsg;
} else if (heartbeatJSON["status"] === DOWN) {
let grafanadowndata = {
@@ -34,10 +30,7 @@ class GrafanaOncall extends NotificationProvider {
message: heartbeatJSON["msg"],
state: "alerting",
};
await axios.post(
notification.GrafanaOncallURL,
grafanadowndata
);
await axios.post(notification.GrafanaOncallURL, grafanadowndata);
return okMsg;
} else if (heartbeatJSON["status"] === UP) {
let grafanaupdata = {
@@ -45,10 +38,7 @@ class GrafanaOncall extends NotificationProvider {
message: heartbeatJSON["msg"],
state: "ok",
};
await axios.post(
notification.GrafanaOncallURL,
grafanaupdata
);
await axios.post(notification.GrafanaOncallURL, grafanaupdata);
return okMsg;
}
} catch (error) {

View File

@@ -0,0 +1,33 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class GtxMessaging extends NotificationProvider {
name = "gtxmessaging";
/**
* @inheritDoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
// The UP/DOWN symbols will be replaced with `???` by gtx-messaging
const text = msg.replaceAll("🔴 ", "").replaceAll("✅ ", "");
try {
const data = new URLSearchParams();
data.append("from", notification.gtxMessagingFrom.trim());
data.append("to", notification.gtxMessagingTo.trim());
data.append("text", text);
const url = `https://rest.gtx-messaging.net/smsc/sendsms/${notification.gtxMessagingApiKey}/json`;
await axios.post(url, data);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = GtxMessaging;

View File

@@ -0,0 +1,52 @@
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
const { setting } = require("../util-server");
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class HeiiOnCall extends NotificationProvider {
name = "HeiiOnCall";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const payload = heartbeatJSON || {};
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorJSON) {
payload["url"] = baseURL + getMonitorRelativeURL(monitorJSON.id);
}
const config = {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + notification.heiiOnCallApiKey,
},
};
const heiiUrl = `https://heiioncall.com/triggers/${notification.heiiOnCallTriggerId}/`;
// docs https://heiioncall.com/docs#manual-triggers
try {
if (!heartbeatJSON) {
// Testing or general notification like certificate expiry
payload["msg"] = msg;
await axios.post(heiiUrl + "alert", payload, config);
return okMsg;
}
if (heartbeatJSON.status === DOWN) {
await axios.post(heiiUrl + "alert", payload, config);
return okMsg;
}
if (heartbeatJSON.status === UP) {
await axios.post(heiiUrl + "resolve", payload, config);
return okMsg;
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = HeiiOnCall;

View File

@@ -9,7 +9,9 @@ class HomeAssistant extends NotificationProvider {
/**
* @inheritdoc
*/
async send(notification, message, monitor = null, heartbeat = null) {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const notificationService = notification?.notificationService || defaultNotificationService;
try {
@@ -17,10 +19,12 @@ class HomeAssistant extends NotificationProvider {
`${notification.homeAssistantUrl.trim().replace(/\/*$/, "")}/api/services/notify/${notificationService}`,
{
title: "Uptime Kuma",
message,
message: msg,
...(notificationService !== "persistent_notification" && { data: {
name: monitor?.name,
status: heartbeat?.status,
name: monitorJSON?.name,
status: heartbeatJSON?.status,
channel: "Uptime Kuma",
icon_url: "https://github.com/louislam/uptime-kuma/blob/master/public/icon.png?raw=true",
} }),
},
{
@@ -31,7 +35,7 @@ class HomeAssistant extends NotificationProvider {
}
);
return "Sent Successfully.";
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}

View File

@@ -0,0 +1,42 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Keep extends NotificationProvider {
name = "Keep";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
try {
let data = {
heartbeat: heartbeatJSON,
monitor: monitorJSON,
msg,
};
let config = {
headers: {
"x-api-key": notification.webhookAPIKey,
"content-type": "application/json",
},
};
let url = notification.webhookURL;
if (url.endsWith("/")) {
url = url.slice(0, -1);
}
let webhookURL = url + "/alerts/event/uptimekuma";
await axios.post(webhookURL, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Keep;

View File

@@ -2,15 +2,15 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Kook extends NotificationProvider {
name = "Kook";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let url = "https://www.kookapp.cn/api/v3/message/create";
const okMsg = "Sent Successfully.";
const url = "https://www.kookapp.cn/api/v3/message/create";
let data = {
target_id: notification.kookGuildID,
content: msg,

View File

@@ -3,16 +3,16 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class Line extends NotificationProvider {
name = "line";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://api.line.me/v2/bot/message/push";
try {
let lineAPIUrl = "https://api.line.me/v2/bot/message/push";
let config = {
headers: {
"Content-Type": "application/json",
@@ -29,7 +29,7 @@ class Line extends NotificationProvider {
}
]
};
await axios.post(lineAPIUrl, testMessage, config);
await axios.post(url, testMessage, config);
} else if (heartbeatJSON["status"] === DOWN) {
let downMessage = {
"to": notification.lineUserID,
@@ -43,7 +43,7 @@ class Line extends NotificationProvider {
}
]
};
await axios.post(lineAPIUrl, downMessage, config);
await axios.post(url, downMessage, config);
} else if (heartbeatJSON["status"] === UP) {
let upMessage = {
"to": notification.lineUserID,
@@ -57,7 +57,7 @@ class Line extends NotificationProvider {
}
]
};
await axios.post(lineAPIUrl, upMessage, config);
await axios.post(url, upMessage, config);
}
return okMsg;
} catch (error) {

View File

@@ -4,16 +4,16 @@ const qs = require("qs");
const { DOWN, UP } = require("../../src/util");
class LineNotify extends NotificationProvider {
name = "LineNotify";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://notify-api.line.me/api/notify";
try {
let lineAPIUrl = "https://notify-api.line.me/api/notify";
let config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
@@ -24,7 +24,7 @@ class LineNotify extends NotificationProvider {
let testMessage = {
"message": msg,
};
await axios.post(lineAPIUrl, qs.stringify(testMessage), config);
await axios.post(url, qs.stringify(testMessage), config);
} else if (heartbeatJSON["status"] === DOWN) {
let downMessage = {
"message": "\n[🔴 Down]\n" +
@@ -32,7 +32,7 @@ class LineNotify extends NotificationProvider {
heartbeatJSON["msg"] + "\n" +
`Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lineAPIUrl, qs.stringify(downMessage), config);
await axios.post(url, qs.stringify(downMessage), config);
} else if (heartbeatJSON["status"] === UP) {
let upMessage = {
"message": "\n[✅ Up]\n" +
@@ -40,7 +40,7 @@ class LineNotify extends NotificationProvider {
heartbeatJSON["msg"] + "\n" +
`Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lineAPIUrl, qs.stringify(upMessage), config);
await axios.post(url, qs.stringify(upMessage), config);
}
return okMsg;
} catch (error) {

View File

@@ -3,28 +3,23 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class LunaSea extends NotificationProvider {
name = "lunasea";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let lunaseaurl = "";
if (notification.lunaseaTarget === "user") {
lunaseaurl = "https://notify.lunasea.app/v1/custom/user/" + notification.lunaseaUserID;
} else {
lunaseaurl = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice;
}
const okMsg = "Sent Successfully.";
const url = "https://notify.lunasea.app/v1";
try {
const target = this.getTarget(notification);
if (heartbeatJSON == null) {
let testdata = {
"title": "Uptime Kuma Alert",
"body": msg,
};
await axios.post(lunaseaurl, testdata);
await axios.post(`${url}/custom/${target}`, testdata);
return okMsg;
}
@@ -35,7 +30,7 @@ class LunaSea extends NotificationProvider {
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lunaseaurl, downdata);
await axios.post(`${url}/custom/${target}`, downdata);
return okMsg;
}
@@ -46,13 +41,25 @@ class LunaSea extends NotificationProvider {
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lunaseaurl, updata);
await axios.post(`${url}/custom/${target}`, updata);
return okMsg;
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
/**
* Generates the lunasea target to send the notification to
* @param {BeanModel} notification Notification details
* @returns {string} The target to send the notification to
*/
getTarget(notification) {
if (notification.lunaseaTarget === "user") {
return "user/" + notification.lunaseaUserID;
}
return "device/" + notification.lunaseaDevice;
}
}

View File

@@ -10,7 +10,7 @@ class Matrix extends NotificationProvider {
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const size = 20;
const randomString = encodeURIComponent(

View File

@@ -3,14 +3,14 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class Mattermost extends NotificationProvider {
name = "mattermost";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
// If heartbeatJSON is null, assume non monitoring notification (Certificate warning) or testing.
@@ -98,10 +98,7 @@ class Mattermost extends NotificationProvider {
},
],
};
await axios.post(
notification.mattermostWebhookUrl,
mattermostdata
);
await axios.post(notification.mattermostWebhookUrl, mattermostdata);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);

View File

@@ -107,7 +107,7 @@ class Nostr extends NotificationProvider {
/**
* Get public keys for recipients
* @param {string} recipients Newline delimited list of recipients
* @returns {nip19.DecodeResult[]} Public keys
* @returns {Promise<nip19.DecodeResult[]>} Public keys
*/
async getPublicKeys(recipients) {
const recipientsList = recipients.split("\n");

View File

@@ -3,14 +3,14 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class Ntfy extends NotificationProvider {
name = "ntfy";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let headers = {};
if (notification.ntfyAuthenticationMethod === "usernamePassword") {
@@ -31,7 +31,7 @@ class Ntfy extends NotificationProvider {
"priority": notification.ntfyPriority,
"tags": [ "test_tube" ],
};
await axios.post(`${notification.ntfyserverurl}`, ntfyTestData, { headers: headers });
await axios.post(notification.ntfyserverurl, ntfyTestData, { headers: headers });
return okMsg;
}
let tags = [];
@@ -54,20 +54,23 @@ class Ntfy extends NotificationProvider {
"priority": priority,
"title": monitorJSON.name + " " + status + " [Uptime-Kuma]",
"tags": tags,
"actions": [
};
if (monitorJSON.url && monitorJSON.url !== "https://") {
data.actions = [
{
"action": "view",
"label": "Open " + monitorJSON.name,
"url": monitorJSON.url,
}
]
};
},
];
}
if (notification.ntfyIcon) {
data.icon = notification.ntfyIcon;
}
await axios.post(`${notification.ntfyserverurl}`, data, { headers: headers });
await axios.post(notification.ntfyserverurl, data, { headers: headers });
return okMsg;

View File

@@ -2,14 +2,15 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Octopush extends NotificationProvider {
name = "octopush";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const urlV2 = "https://api.octopush.com/v1/public/sms-campaign/send";
const urlV1 = "https://www.octopush-dm.com/api/sms/json";
try {
// Default - V2
@@ -33,7 +34,7 @@ class Octopush extends NotificationProvider {
"purpose": "alert",
"sender": notification.octopushSenderName
};
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config);
await axios.post(urlV2, data, config);
} else if (notification.octopushVersion === "1") {
let data = {
"user_login": notification.octopushDMLogin,
@@ -55,7 +56,7 @@ class Octopush extends NotificationProvider {
// V1 API returns 200 even on error so we must check
// response data
let response = await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config);
let response = await axios.post(urlV1, {}, config);
if ("error_code" in response.data) {
if (response.data.error_code !== "000") {
this.throwGeneralAxiosError(`Octopush error ${JSON.stringify(response.data)}`);

View File

@@ -2,23 +2,23 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class OneBot extends NotificationProvider {
name = "OneBot";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let httpAddr = notification.httpAddr;
if (!httpAddr.startsWith("http")) {
httpAddr = "http://" + httpAddr;
let url = notification.httpAddr;
if (!url.startsWith("http")) {
url = "http://" + url;
}
if (!httpAddr.endsWith("/")) {
httpAddr += "/";
if (!url.endsWith("/")) {
url += "/";
}
let onebotAPIUrl = httpAddr + "send_msg";
url += "send_msg";
let config = {
headers: {
"Content-Type": "application/json",
@@ -37,7 +37,7 @@ class OneBot extends NotificationProvider {
data["message_type"] = "private";
data["user_id"] = notification.recieverId;
}
await axios.post(onebotAPIUrl, data, config);
await axios.post(url, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);

View File

@@ -4,10 +4,9 @@ const { UP, DOWN } = require("../../src/util");
const opsgenieAlertsUrlEU = "https://api.eu.opsgenie.com/v2/alerts";
const opsgenieAlertsUrlUS = "https://api.opsgenie.com/v2/alerts";
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
class Opsgenie extends NotificationProvider {
name = "Opsgenie";
/**

View File

@@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class PromoSMS extends NotificationProvider {
name = "promosms";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://promosms.com/api/rest/v3_2/sms";
if (notification.promosmsAllowLongSMS === undefined) {
notification.promosmsAllowLongSMS = false;
@@ -36,7 +36,7 @@ class PromoSMS extends NotificationProvider {
"sender": notification.promosmsSenderName
};
let resp = await axios.post("https://promosms.com/api/rest/v3_2/sms", data, config);
let resp = await axios.post(url, data, config);
if (resp.data.response.status !== 0) {
let error = "Something gone wrong. Api returned " + resp.data.response.status + ".";

View File

@@ -4,17 +4,16 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class Pushbullet extends NotificationProvider {
name = "pushbullet";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://api.pushbullet.com/v2/pushes";
try {
let pushbulletUrl = "https://api.pushbullet.com/v2/pushes";
let config = {
headers: {
"Access-Token": notification.pushbulletAccessToken,
@@ -27,7 +26,7 @@ class Pushbullet extends NotificationProvider {
"title": "Uptime Kuma Alert",
"body": msg,
};
await axios.post(pushbulletUrl, data, config);
await axios.post(url, data, config);
} else if (heartbeatJSON["status"] === DOWN) {
let downData = {
"type": "note",
@@ -36,7 +35,7 @@ class Pushbullet extends NotificationProvider {
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
};
await axios.post(pushbulletUrl, downData, config);
await axios.post(url, downData, config);
} else if (heartbeatJSON["status"] === UP) {
let upData = {
"type": "note",
@@ -45,7 +44,7 @@ class Pushbullet extends NotificationProvider {
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
};
await axios.post(pushbulletUrl, upData, config);
await axios.post(url, upData, config);
}
return okMsg;
} catch (error) {

View File

@@ -3,17 +3,15 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class PushDeer extends NotificationProvider {
name = "PushDeer";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let endpoint = "/message/push";
let serverUrl = notification.pushdeerServer || "https://api2.pushdeer.com";
let pushdeerlink = `${serverUrl.trim().replace(/\/*$/, "")}${endpoint}`;
const okMsg = "Sent Successfully.";
const serverUrl = notification.pushdeerServer || "https://api2.pushdeer.com";
const url = `${serverUrl.trim().replace(/\/*$/, "")}/message/push`;
let valid = msg != null && monitorJSON != null && heartbeatJSON != null;
@@ -34,7 +32,7 @@ class PushDeer extends NotificationProvider {
};
try {
let res = await axios.post(pushdeerlink, data);
let res = await axios.post(url, data);
if ("error" in res.data) {
let error = res.data.error;

View File

@@ -2,15 +2,14 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Pushover extends NotificationProvider {
name = "pushover";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let pushoverlink = "https://api.pushover.net/1/messages.json";
const okMsg = "Sent Successfully.";
const url = "https://api.pushover.net/1/messages.json";
let data = {
"message": msg,
@@ -33,11 +32,11 @@ class Pushover extends NotificationProvider {
try {
if (heartbeatJSON == null) {
await axios.post(pushoverlink, data);
await axios.post(url, data);
return okMsg;
} else {
data.message += `\n<b>Time (${heartbeatJSON["timezone"]})</b>:${heartbeatJSON["localDateTime"]}`;
await axios.post(pushoverlink, data);
await axios.post(url, data);
return okMsg;
}
} catch (error) {

View File

@@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Pushy extends NotificationProvider {
name = "pushy";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, {

View File

@@ -5,14 +5,14 @@ const { setting } = require("../util-server");
const { getMonitorRelativeURL, DOWN } = require("../../src/util");
class RocketChat extends NotificationProvider {
name = "rocket.chat";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
if (heartbeatJSON == null) {
let data = {

View File

@@ -3,14 +3,14 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class ServerChan extends NotificationProvider {
name = "ServerChan";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
await axios.post(`https://sctapi.ftqq.com/${notification.serverChanSendKey}.send`, {
"title": this.checkStatus(heartbeatJSON, monitorJSON),

View File

@@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class SerwerSMS extends NotificationProvider {
name = "serwersms";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://api2.serwersms.pl/messages/send_sms";
try {
let config = {
@@ -25,7 +25,7 @@ class SerwerSMS extends NotificationProvider {
"sender": notification.serwersmsSenderName,
};
let resp = await axios.post("https://api2.serwersms.pl/messages/send_sms", data, config);
let resp = await axios.post(url, data, config);
if (!resp.data.success) {
if (resp.data.error) {

View File

@@ -0,0 +1,78 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class SevenIO extends NotificationProvider {
name = "SevenIO";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const data = {
to: notification.sevenioTo,
from: notification.sevenioSender || "Uptime Kuma",
text: msg,
};
const config = {
baseURL: "https://gateway.seven.io/api/",
headers: {
"Content-Type": "application/json",
"X-API-Key": notification.sevenioApiKey,
},
};
try {
// testing or certificate expiry notification
if (heartbeatJSON == null) {
await axios.post("sms", data, config);
return okMsg;
}
let address = "";
switch (monitorJSON["type"]) {
case "ping":
address = monitorJSON["hostname"];
break;
case "port":
case "dns":
case "gamedig":
case "steam":
address = monitorJSON["hostname"];
if (monitorJSON["port"]) {
address += ":" + monitorJSON["port"];
}
break;
default:
if (![ "https://", "http://", "" ].includes(monitorJSON["url"])) {
address = monitorJSON["url"];
}
break;
}
if (address !== "") {
address = `(${address}) `;
}
// If heartbeatJSON is not null, we go into the normal alerting loop.
if (heartbeatJSON["status"] === DOWN) {
data.text = `Your service ${monitorJSON["name"]} ${address}went down at ${heartbeatJSON["localDateTime"]} ` +
`(${heartbeatJSON["timezone"]}). Error: ${heartbeatJSON["msg"]}`;
} else if (heartbeatJSON["status"] === UP) {
data.text = `Your service ${monitorJSON["name"]} ${address}went back up at ${heartbeatJSON["localDateTime"]} ` +
`(${heartbeatJSON["timezone"]}).`;
}
await axios.post("sms", data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = SevenIO;

View File

@@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Signal extends NotificationProvider {
name = "signal";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let data = {

View File

@@ -4,7 +4,6 @@ const { setSettings, setting } = require("../util-server");
const { getMonitorRelativeURL, UP } = require("../../src/util");
class Slack extends NotificationProvider {
name = "slack";
/**
@@ -27,11 +26,98 @@ class Slack extends NotificationProvider {
}
}
/**
* Builds the actions available in the slack message
* @param {string} baseURL Uptime Kuma base URL
* @param {object} monitorJSON The monitor config
* @returns {Array} The relevant action objects
*/
static buildActions(baseURL, monitorJSON) {
const actions = [];
if (baseURL) {
actions.push({
"type": "button",
"text": {
"type": "plain_text",
"text": "Visit Uptime Kuma",
},
"value": "Uptime-Kuma",
"url": baseURL + getMonitorRelativeURL(monitorJSON.id),
});
}
if (monitorJSON.url) {
actions.push({
"type": "button",
"text": {
"type": "plain_text",
"text": "Visit site",
},
"value": "Site",
"url": monitorJSON.url,
});
}
return actions;
}
/**
* Builds the different blocks the Slack message consists of.
* @param {string} baseURL Uptime Kuma base URL
* @param {object} monitorJSON The monitor object
* @param {object} heartbeatJSON The heartbeat object
* @param {string} title The message title
* @param {string} msg The message body
* @returns {Array<object>} The rich content blocks for the Slack message
*/
static buildBlocks(baseURL, monitorJSON, heartbeatJSON, title, msg) {
//create an array to dynamically add blocks
const blocks = [];
// the header block
blocks.push({
"type": "header",
"text": {
"type": "plain_text",
"text": title,
},
});
// the body block, containing the details
blocks.push({
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Message*\n" + msg,
},
{
"type": "mrkdwn",
"text": `*Time (${heartbeatJSON["timezone"]})*\n${heartbeatJSON["localDateTime"]}`,
}
],
});
const actions = this.buildActions(baseURL, monitorJSON);
if (actions.length > 0) {
//the actions block, containing buttons
blocks.push({
"type": "actions",
"elements": actions,
});
}
return blocks;
}
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
if (notification.slackchannelnotify) {
msg += " <!channel>";
@@ -49,35 +135,18 @@ class Slack extends NotificationProvider {
return okMsg;
}
const textMsg = "Uptime Kuma Alert";
const baseURL = await setting("primaryBaseURL");
const title = "Uptime Kuma Alert";
let data = {
"text": `${textMsg}\n${msg}`,
"text": `${title}\n${msg}`,
"channel": notification.slackchannel,
"username": notification.slackusername,
"icon_emoji": notification.slackiconemo,
"attachments": [
{
"color": (heartbeatJSON["status"] === UP) ? "#2eb886" : "#e01e5a",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": textMsg,
},
},
{
"type": "section",
"fields": [{
"type": "mrkdwn",
"text": "*Message*\n" + msg,
},
{
"type": "mrkdwn",
"text": `*Time (${heartbeatJSON["timezone"]})*\n${heartbeatJSON["localDateTime"]}`,
}],
}
],
"blocks": Slack.buildBlocks(baseURL, monitorJSON, heartbeatJSON, title, msg),
}
]
};
@@ -86,26 +155,6 @@ class Slack extends NotificationProvider {
await Slack.deprecateURL(notification.slackbutton);
}
const baseURL = await setting("primaryBaseURL");
// Button
if (baseURL) {
data.attachments.forEach(element => {
element.blocks.push({
"type": "actions",
"elements": [{
"type": "button",
"text": {
"type": "plain_text",
"text": "Visit Uptime Kuma",
},
"value": "Uptime-Kuma",
"url": baseURL + getMonitorRelativeURL(monitorJSON.id),
}],
});
});
}
await axios.post(notification.slackwebhookURL, data);
return okMsg;
} catch (error) {

View File

@@ -8,7 +8,9 @@ class SMSC extends NotificationProvider {
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://smsc.kz/sys/send.php?";
try {
let config = {
headers: {
@@ -29,7 +31,7 @@ class SMSC extends NotificationProvider {
getArray.push("sender=" + notification.smscSenderName);
}
let resp = await axios.get("https://smsc.kz/sys/send.php?" + getArray.join("&"), config);
let resp = await axios.get(url + getArray.join("&"), config);
if (resp.data.id === undefined) {
let error = `Something gone wrong. Api returned code ${resp.data.error_code}: ${resp.data.error}`;
this.throwGeneralAxiosError(error);

View File

@@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class SMSEagle extends NotificationProvider {
name = "SMSEagle";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let config = {

View File

@@ -2,23 +2,24 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class SMSManager extends NotificationProvider {
name = "SMSManager";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const url = "https://http-api.smsmanager.cz/Send";
try {
let data = {
apikey: notification.smsmanagerApiKey,
endpoint: "https://http-api.smsmanager.cz/Send",
message: msg.replace(/[^\x00-\x7F]/g, ""),
to: notification.numbers,
messageType: notification.messageType,
number: notification.numbers,
gateway: notification.messageType,
};
await axios.get(`${data.endpoint}?apikey=${data.apikey}&message=${data.message}&number=${data.to}&gateway=${data.messageType}`);
return "SMS sent sucessfully.";
await axios.get(`${url}?apikey=${data.apikey}&message=${data.message}&number=${data.number}&gateway=${data.messageType}`);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}

View File

@@ -0,0 +1,46 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class SMSPartner extends NotificationProvider {
name = "SMSPartner";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const url = "https://api.smspartner.fr/v1/send";
try {
// smspartner does not support non ascii characters and only a maximum 639 characters
let cleanMsg = msg.replace(/[^\x00-\x7F]/g, "").substring(0, 639);
let data = {
"apiKey": notification.smspartnerApikey,
"sender": notification.smspartnerSenderName.substring(0, 11),
"phoneNumbers": notification.smspartnerPhoneNumber,
"message": cleanMsg,
};
let config = {
headers: {
"Content-Type": "application/json",
"cache-control": "no-cache",
"Accept": "application/json",
}
};
let resp = await axios.post(url, data, config);
if (resp.data.success !== true) {
throw Error(`Api returned ${resp.data.response.status}.`);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = SMSPartner;

View File

@@ -4,13 +4,13 @@ const { DOWN } = require("../../src/util");
const { Liquid } = require("liquidjs");
class SMTP extends NotificationProvider {
name = "smtp";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const config = {
host: notification.smtpHost,
@@ -76,7 +76,7 @@ class SMTP extends NotificationProvider {
text: body,
});
return "Sent Successfully.";
return okMsg;
}
/**

View File

@@ -3,14 +3,13 @@ const axios = require("axios");
const { DOWN } = require("../../src/util");
class Squadcast extends NotificationProvider {
name = "squadcast";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {

View File

@@ -4,14 +4,14 @@ const { setting } = require("../util-server");
const { getMonitorRelativeURL } = require("../../src/util");
class Stackfield extends NotificationProvider {
name = "stackfield";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null) {
let okMsg = "Sent Successfully.";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
try {
// Stackfield message formatting: https://www.stackfield.com/help/formatting-messages-2001

View File

@@ -1,6 +1,7 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
const { setting } = require("../util-server");
const { DOWN, UP, getMonitorRelativeURL } = require("../../src/util");
class Teams extends NotificationProvider {
name = "teams";
@@ -9,89 +10,172 @@ class Teams extends NotificationProvider {
* Generate the message to send
* @param {const} status The status constant
* @param {string} monitorName Name of monitor
* @param {boolean} withStatusSymbol If the status should be prepended as symbol
* @returns {string} Status message
*/
_statusMessageFactory = (status, monitorName) => {
_statusMessageFactory = (status, monitorName, withStatusSymbol) => {
if (status === DOWN) {
return `🔴 Application [${monitorName}] went down`;
return (withStatusSymbol ? "🔴 " : "") + `[${monitorName}] went down`;
} else if (status === UP) {
return `✅ Application [${monitorName}] is back online`;
return (withStatusSymbol ? "✅ " : "") + `[${monitorName}] is back online`;
}
return "Notification";
};
/**
* Select theme color to use based on status
* Select the style to use based on status
* @param {const} status The status constant
* @returns {string} Selected color in hex RGB format
* @returns {string} Selected style for adaptive cards
*/
_getThemeColor = (status) => {
_getStyle = (status) => {
if (status === DOWN) {
return "ff0000";
return "attention";
}
if (status === UP) {
return "00e804";
return "good";
}
return "008cff";
return "emphasis";
};
/**
* Generate payload for notification
* @param {object} args Method arguments
* @param {const} args.status The status of the monitor
* @param {string} args.monitorMessage Message to send
* @param {string} args.monitorName Name of monitor affected
* @param {string} args.monitorUrl URL of monitor affected
* @param {object} args.heartbeatJSON Heartbeat details
* @param {string} args.monitorName Name of the monitor affected
* @param {string} args.monitorUrl URL of the monitor affected
* @param {string} args.dashboardUrl URL of the dashboard affected
* @returns {object} Notification payload
*/
_notificationPayloadFactory = ({
status,
monitorMessage,
heartbeatJSON,
monitorName,
monitorUrl,
dashboardUrl,
}) => {
const notificationMessage = this._statusMessageFactory(
status,
monitorName
);
const status = heartbeatJSON?.status;
const facts = [];
const actions = [];
if (dashboardUrl) {
actions.push({
"type": "Action.OpenUrl",
"title": "Visit Uptime Kuma",
"url": dashboardUrl
});
}
if (heartbeatJSON?.msg) {
facts.push({
title: "Description",
value: heartbeatJSON.msg,
});
}
if (monitorName) {
facts.push({
name: "Monitor",
title: "Monitor",
value: monitorName,
});
}
if (monitorUrl && monitorUrl !== "https://") {
facts.push({
name: "URL",
value: monitorUrl,
title: "URL",
// format URL as markdown syntax, to be clickable
value: `[${monitorUrl}](${monitorUrl})`,
});
actions.push({
"type": "Action.OpenUrl",
"title": "Visit Monitor URL",
"url": monitorUrl
});
}
return {
"@context": "https://schema.org/extensions",
"@type": "MessageCard",
themeColor: this._getThemeColor(status),
summary: notificationMessage,
sections: [
if (heartbeatJSON?.localDateTime) {
facts.push({
title: "Time",
value: heartbeatJSON.localDateTime + (heartbeatJSON.timezone ? ` (${heartbeatJSON.timezone})` : ""),
});
}
const payload = {
"type": "message",
// message with status prefix as notification text
"summary": this._statusMessageFactory(status, monitorName, true),
"attachments": [
{
activityImage:
"https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png",
activityTitle: "**Uptime Kuma**",
},
{
activityTitle: notificationMessage,
},
{
activityTitle: "**Description**",
text: monitorMessage,
facts,
},
],
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": "",
"content": {
"type": "AdaptiveCard",
"body": [
{
"type": "Container",
"verticalContentAlignment": "Center",
"items": [
{
"type": "ColumnSet",
"style": this._getStyle(status),
"columns": [
{
"type": "Column",
"width": "auto",
"verticalContentAlignment": "Center",
"items": [
{
"type": "Image",
"width": "32px",
"style": "Person",
"url": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png",
"altText": "Uptime Kuma Logo"
}
]
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": `**${this._statusMessageFactory(status, monitorName, false)}**`,
},
{
"type": "TextBlock",
"size": "Small",
"weight": "Default",
"text": "Uptime Kuma Alert",
"isSubtle": true,
"spacing": "None"
}
]
}
]
}
]
},
{
"type": "FactSet",
"separator": false,
"facts": facts
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
}
]
};
if (actions) {
payload.attachments[0].content.body.push({
"type": "ActionSet",
"actions": actions,
});
}
return payload;
};
/**
@@ -112,7 +196,9 @@ class Teams extends NotificationProvider {
*/
_handleGeneralNotification = (webhookUrl, msg) => {
const payload = this._notificationPayloadFactory({
monitorMessage: msg
heartbeatJSON: {
msg: msg
}
});
return this._sendNotification(webhookUrl, payload);
@@ -122,7 +208,7 @@ class Teams extends NotificationProvider {
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
if (heartbeatJSON == null) {
@@ -130,26 +216,32 @@ class Teams extends NotificationProvider {
return okMsg;
}
let url;
let monitorUrl;
switch (monitorJSON["type"]) {
case "http":
case "keywork":
url = monitorJSON["url"];
monitorUrl = monitorJSON["url"];
break;
case "docker":
url = monitorJSON["docker_host"];
monitorUrl = monitorJSON["docker_host"];
break;
default:
url = monitorJSON["hostname"];
monitorUrl = monitorJSON["hostname"];
break;
}
const baseURL = await setting("primaryBaseURL");
let dashboardUrl;
if (baseURL) {
dashboardUrl = baseURL + getMonitorRelativeURL(monitorJSON.id);
}
const payload = this._notificationPayloadFactory({
monitorMessage: heartbeatJSON.msg,
heartbeatJSON: heartbeatJSON,
monitorName: monitorJSON.name,
monitorUrl: url,
status: heartbeatJSON.status,
monitorUrl: monitorUrl,
dashboardUrl: dashboardUrl,
});
await this._sendNotification(notification.webhookUrl, payload);

View File

@@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class TechulusPush extends NotificationProvider {
name = "PushByTechulus";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, {

View File

@@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Telegram extends NotificationProvider {
name = "telegram";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
const url = "https://api.telegram.org";
try {
let params = {
@@ -22,7 +22,7 @@ class Telegram extends NotificationProvider {
params.message_thread_id = notification.telegramMessageThreadID;
}
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
await axios.get(`${url}/bot${notification.telegramBotToken}/sendMessage`, {
params: params,
});
return okMsg;

View File

@@ -2,26 +2,21 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Twilio extends NotificationProvider {
name = "twilio";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
let okMsg = "Sent Successfully.";
let accountSID = notification.twilioAccountSID;
let apiKey = notification.twilioApiKey ? notification.twilioApiKey : accountSID;
let authToken = notification.twilioAuthToken;
let apiKey = notification.twilioApiKey ? notification.twilioApiKey : notification.twilioAccountSID;
try {
let config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
"Authorization": "Basic " + Buffer.from(apiKey + ":" + authToken).toString("base64"),
"Authorization": "Basic " + Buffer.from(apiKey + ":" + notification.twilioAuthToken).toString("base64"),
}
};
@@ -30,9 +25,7 @@ class Twilio extends NotificationProvider {
data.append("From", notification.twilioFromNumber);
data.append("Body", msg);
let url = "https://api.twilio.com/2010-04-01/Accounts/" + accountSID + "/Messages.json";
await axios.post(url, data, config);
await axios.post(`https://api.twilio.com/2010-04-01/Accounts/${(notification.twilioAccountSID)}/Messages.json`, data, config);
return okMsg;
} catch (error) {

View File

@@ -4,14 +4,13 @@ const FormData = require("form-data");
const { Liquid } = require("liquidjs");
class Webhook extends NotificationProvider {
name = "webhook";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let data = {

View File

@@ -3,24 +3,22 @@ const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class WeCom extends NotificationProvider {
name = "WeCom";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
const okMsg = "Sent Successfully.";
try {
let WeComUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + notification.weComBotKey;
let config = {
headers: {
"Content-Type": "application/json"
}
};
let body = this.composeMessage(heartbeatJSON, msg);
await axios.post(WeComUrl, body, config);
await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${notification.weComBotKey}`, body, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);

View File

@@ -0,0 +1,39 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Whapi extends NotificationProvider {
name = "whapi";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
try {
const config = {
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer " + notification.whapiAuthToken,
}
};
let data = {
"to": notification.whapiRecipient,
"body": msg,
};
let url = (notification.whapiApiUrl || "https://gate.whapi.cloud/").replace(/\/+$/, "") + "/messages/text";
await axios.post(url, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Whapi;

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