Merge branch 'master' into import-export
This commit is contained in:
		
						commit
						62712f5cc4
					
				
					 40 changed files with 1082 additions and 785 deletions
				
			
		|  | @ -17,7 +17,8 @@ module.exports = { | |||
|     }, | ||||
|     rules: { | ||||
|         "camelcase": ["warn", { | ||||
|             "properties": "never" | ||||
|             "properties": "never", | ||||
|             "ignoreImports": true | ||||
|         }], | ||||
|         // override/add rules settings here, such as:
 | ||||
|         // 'vue/no-unused-vars': 'error'
 | ||||
|  |  | |||
							
								
								
									
										26
									
								
								server/notification-providers/apprise.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								server/notification-providers/apprise.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const child_process = require("child_process"); | ||||
| 
 | ||||
| class Apprise extends NotificationProvider { | ||||
| 
 | ||||
|     name = "apprise"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL]) | ||||
| 
 | ||||
|         let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found"; | ||||
| 
 | ||||
|         if (output) { | ||||
| 
 | ||||
|             if (! output.includes("ERROR")) { | ||||
|                 return "Sent Successfully"; | ||||
|             } | ||||
| 
 | ||||
|             throw new Error(output) | ||||
|         } else { | ||||
|             return "No output from apprise"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Apprise; | ||||
							
								
								
									
										105
									
								
								server/notification-providers/discord.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								server/notification-providers/discord.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,105 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| const { DOWN, UP } = require("../../src/util"); | ||||
| 
 | ||||
| class Discord extends NotificationProvider { | ||||
| 
 | ||||
|     name = "discord"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             const discordDisplayName = notification.discordUsername || "Uptime Kuma"; | ||||
| 
 | ||||
|             // If heartbeatJSON is null, assume we're testing.
 | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let discordtestdata = { | ||||
|                     username: discordDisplayName, | ||||
|                     content: msg, | ||||
|                 } | ||||
|                 await axios.post(notification.discordWebhookUrl, discordtestdata) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             let url; | ||||
| 
 | ||||
|             if (monitorJSON["type"] === "port") { | ||||
|                 url = monitorJSON["hostname"]; | ||||
|                 if (monitorJSON["port"]) { | ||||
|                     url += ":" + monitorJSON["port"]; | ||||
|                 } | ||||
| 
 | ||||
|             } else { | ||||
|                 url = monitorJSON["url"]; | ||||
|             } | ||||
| 
 | ||||
|             // If heartbeatJSON is not null, we go into the normal alerting loop.
 | ||||
|             if (heartbeatJSON["status"] == DOWN) { | ||||
|                 let discorddowndata = { | ||||
|                     username: discordDisplayName, | ||||
|                     embeds: [{ | ||||
|                         title: "❌ Your service " + monitorJSON["name"] + " went down. ❌", | ||||
|                         color: 16711680, | ||||
|                         timestamp: heartbeatJSON["time"], | ||||
|                         fields: [ | ||||
|                             { | ||||
|                                 name: "Service Name", | ||||
|                                 value: monitorJSON["name"], | ||||
|                             }, | ||||
|                             { | ||||
|                                 name: "Service URL", | ||||
|                                 value: url, | ||||
|                             }, | ||||
|                             { | ||||
|                                 name: "Time (UTC)", | ||||
|                                 value: heartbeatJSON["time"], | ||||
|                             }, | ||||
|                             { | ||||
|                                 name: "Error", | ||||
|                                 value: heartbeatJSON["msg"], | ||||
|                             }, | ||||
|                         ], | ||||
|                     }], | ||||
|                 } | ||||
|                 await axios.post(notification.discordWebhookUrl, discorddowndata) | ||||
|                 return okMsg; | ||||
| 
 | ||||
|             } else if (heartbeatJSON["status"] == UP) { | ||||
|                 let discordupdata = { | ||||
|                     username: discordDisplayName, | ||||
|                     embeds: [{ | ||||
|                         title: "✅ Your service " + monitorJSON["name"] + " is up! ✅", | ||||
|                         color: 65280, | ||||
|                         timestamp: heartbeatJSON["time"], | ||||
|                         fields: [ | ||||
|                             { | ||||
|                                 name: "Service Name", | ||||
|                                 value: monitorJSON["name"], | ||||
|                             }, | ||||
|                             { | ||||
|                                 name: "Service URL", | ||||
|                                 value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url, | ||||
|                             }, | ||||
|                             { | ||||
|                                 name: "Time (UTC)", | ||||
|                                 value: heartbeatJSON["time"], | ||||
|                             }, | ||||
|                             { | ||||
|                                 name: "Ping", | ||||
|                                 value: heartbeatJSON["ping"] + "ms", | ||||
|                             }, | ||||
|                         ], | ||||
|                     }], | ||||
|                 } | ||||
|                 await axios.post(notification.discordWebhookUrl, discordupdata) | ||||
|                 return okMsg; | ||||
|             } | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| module.exports = Discord; | ||||
							
								
								
									
										28
									
								
								server/notification-providers/gotify.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								server/notification-providers/gotify.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Gotify extends NotificationProvider { | ||||
| 
 | ||||
|     name = "gotify"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         try { | ||||
|             if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) { | ||||
|                 notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1); | ||||
|             } | ||||
|             await axios.post(`${notification.gotifyserverurl}/message?token=${notification.gotifyapplicationToken}`, { | ||||
|                 "message": msg, | ||||
|                 "priority": notification.gotifyPriority || 8, | ||||
|                 "title": "Uptime-Kuma", | ||||
|             }) | ||||
| 
 | ||||
|             return okMsg; | ||||
| 
 | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Gotify; | ||||
							
								
								
									
										60
									
								
								server/notification-providers/line.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								server/notification-providers/line.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| const { DOWN, UP } = require("../../src/util"); | ||||
| 
 | ||||
| class Line extends NotificationProvider { | ||||
| 
 | ||||
|     name = "line"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         try { | ||||
|             let lineAPIUrl = "https://api.line.me/v2/bot/message/push"; | ||||
|             let config = { | ||||
|                 headers: { | ||||
|                     "Content-Type": "application/json", | ||||
|                     "Authorization": "Bearer " + notification.lineChannelAccessToken | ||||
|                 } | ||||
|             }; | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let testMessage = { | ||||
|                     "to": notification.lineUserID, | ||||
|                     "messages": [ | ||||
|                         { | ||||
|                             "type": "text", | ||||
|                             "text": "Test Successful!" | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|                 await axios.post(lineAPIUrl, testMessage, config) | ||||
|             } else if (heartbeatJSON["status"] == DOWN) { | ||||
|                 let downMessage = { | ||||
|                     "to": notification.lineUserID, | ||||
|                     "messages": [ | ||||
|                         { | ||||
|                             "type": "text", | ||||
|                             "text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|                 await axios.post(lineAPIUrl, downMessage, config) | ||||
|             } else if (heartbeatJSON["status"] == UP) { | ||||
|                 let upMessage = { | ||||
|                     "to": notification.lineUserID, | ||||
|                     "messages": [ | ||||
|                         { | ||||
|                             "type": "text", | ||||
|                             "text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|                 await axios.post(lineAPIUrl, upMessage, config) | ||||
|             } | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Line; | ||||
							
								
								
									
										48
									
								
								server/notification-providers/lunasea.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								server/notification-providers/lunasea.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| const { DOWN, UP } = require("../../src/util"); | ||||
| 
 | ||||
| class LunaSea extends NotificationProvider { | ||||
| 
 | ||||
|     name = "lunasea"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice | ||||
| 
 | ||||
|         try { | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let testdata = { | ||||
|                     "title": "Uptime Kuma Alert", | ||||
|                     "body": "Testing Successful.", | ||||
|                 } | ||||
|                 await axios.post(lunaseadevice, testdata) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             if (heartbeatJSON["status"] == DOWN) { | ||||
|                 let downdata = { | ||||
|                     "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                     "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                 } | ||||
|                 await axios.post(lunaseadevice, downdata) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             if (heartbeatJSON["status"] == UP) { | ||||
|                 let updata = { | ||||
|                     "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                     "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                 } | ||||
|                 await axios.post(lunaseadevice, updata) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = LunaSea; | ||||
							
								
								
									
										123
									
								
								server/notification-providers/mattermost.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								server/notification-providers/mattermost.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| const { DOWN, UP } = require("../../src/util"); | ||||
| 
 | ||||
| class Mattermost extends NotificationProvider { | ||||
| 
 | ||||
|     name = "mattermost"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         try { | ||||
|             const mattermostUserName = notification.mattermostusername || "Uptime Kuma"; | ||||
|             // If heartbeatJSON is null, assume we're testing.
 | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let mattermostTestData = { | ||||
|                     username: mattermostUserName, | ||||
|                     text: msg, | ||||
|                 } | ||||
|                 await axios.post(notification.mattermostWebhookUrl, mattermostTestData) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             const mattermostChannel = notification.mattermostchannel; | ||||
|             const mattermostIconEmoji = notification.mattermosticonemo; | ||||
|             const mattermostIconUrl = notification.mattermosticonurl; | ||||
| 
 | ||||
|             if (heartbeatJSON["status"] == DOWN) { | ||||
|                 let mattermostdowndata = { | ||||
|                     username: mattermostUserName, | ||||
|                     text: "Uptime Kuma Alert", | ||||
|                     channel: mattermostChannel, | ||||
|                     icon_emoji: mattermostIconEmoji, | ||||
|                     icon_url: mattermostIconUrl, | ||||
|                     attachments: [ | ||||
|                         { | ||||
|                             fallback: | ||||
|                                 "Your " + | ||||
|                                 monitorJSON["name"] + | ||||
|                                 " service went down.", | ||||
|                             color: "#FF0000", | ||||
|                             title: | ||||
|                                 "❌ " + | ||||
|                                 monitorJSON["name"] + | ||||
|                                 " service went down. ❌", | ||||
|                             title_link: monitorJSON["url"], | ||||
|                             fields: [ | ||||
|                                 { | ||||
|                                     short: true, | ||||
|                                     title: "Service Name", | ||||
|                                     value: monitorJSON["name"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     short: true, | ||||
|                                     title: "Time (UTC)", | ||||
|                                     value: heartbeatJSON["time"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     short: false, | ||||
|                                     title: "Error", | ||||
|                                     value: heartbeatJSON["msg"], | ||||
|                                 }, | ||||
|                             ], | ||||
|                         }, | ||||
|                     ], | ||||
|                 }; | ||||
|                 await axios.post( | ||||
|                     notification.mattermostWebhookUrl, | ||||
|                     mattermostdowndata | ||||
|                 ); | ||||
|                 return okMsg; | ||||
|             } else if (heartbeatJSON["status"] == UP) { | ||||
|                 let mattermostupdata = { | ||||
|                     username: mattermostUserName, | ||||
|                     text: "Uptime Kuma Alert", | ||||
|                     channel: mattermostChannel, | ||||
|                     icon_emoji: mattermostIconEmoji, | ||||
|                     icon_url: mattermostIconUrl, | ||||
|                     attachments: [ | ||||
|                         { | ||||
|                             fallback: | ||||
|                                 "Your " + | ||||
|                                 monitorJSON["name"] + | ||||
|                                 " service went up!", | ||||
|                             color: "#32CD32", | ||||
|                             title: | ||||
|                                 "✅ " + | ||||
|                                 monitorJSON["name"] + | ||||
|                                 " service went up! ✅", | ||||
|                             title_link: monitorJSON["url"], | ||||
|                             fields: [ | ||||
|                                 { | ||||
|                                     short: true, | ||||
|                                     title: "Service Name", | ||||
|                                     value: monitorJSON["name"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     short: true, | ||||
|                                     title: "Time (UTC)", | ||||
|                                     value: heartbeatJSON["time"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     short: false, | ||||
|                                     title: "Ping", | ||||
|                                     value: heartbeatJSON["ping"] + "ms", | ||||
|                                 }, | ||||
|                             ], | ||||
|                         }, | ||||
|                     ], | ||||
|                 }; | ||||
|                 await axios.post( | ||||
|                     notification.mattermostWebhookUrl, | ||||
|                     mattermostupdata | ||||
|                 ); | ||||
|                 return okMsg; | ||||
|             } | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Mattermost; | ||||
							
								
								
									
										36
									
								
								server/notification-providers/notification-provider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								server/notification-providers/notification-provider.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| class NotificationProvider { | ||||
| 
 | ||||
|     /** | ||||
|      * Notification Provider Name | ||||
|      * @type string | ||||
|      */ | ||||
|     name = undefined; | ||||
| 
 | ||||
|     /** | ||||
|      * @param notification : BeanModel | ||||
|      * @param msg : string General Message | ||||
|      * @param monitorJSON : object Monitor details (For Up/Down only) | ||||
|      * @param heartbeatJSON : object Heartbeat details (For Up/Down only) | ||||
|      * @returns {Promise<string>} Return Successful Message | ||||
|      * Throw Error with fail msg | ||||
|      */ | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         throw new Error("Have to override Notification.send(...)"); | ||||
|     } | ||||
| 
 | ||||
|     throwGeneralAxiosError(error) { | ||||
|         let msg = "Error: " + error + " "; | ||||
| 
 | ||||
|         if (error.response && error.response.data) { | ||||
|             if (typeof error.response.data === "string") { | ||||
|                 msg += error.response.data; | ||||
|             } else { | ||||
|                 msg += JSON.stringify(error.response.data) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         throw new Error(msg) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = NotificationProvider; | ||||
							
								
								
									
										40
									
								
								server/notification-providers/octopush.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								server/notification-providers/octopush.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Octopush extends NotificationProvider { | ||||
| 
 | ||||
|     name = "octopush"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             let config = { | ||||
|                 headers: { | ||||
|                     "api-key": notification.octopushAPIKey, | ||||
|                     "api-login": notification.octopushLogin, | ||||
|                     "cache-control": "no-cache" | ||||
|                 } | ||||
|             }; | ||||
|             let data = { | ||||
|                 "recipients": [ | ||||
|                     { | ||||
|                         "phone_number": notification.octopushPhoneNumber | ||||
|                     } | ||||
|                 ], | ||||
|                 //octopush not supporting non ascii char
 | ||||
|                 "text": msg.replace(/[^\x00-\x7F]/g, ""), | ||||
|                 "type": notification.octopushSMSType, | ||||
|                 "purpose": "alert", | ||||
|                 "sender": notification.octopushSenderName | ||||
|             }; | ||||
| 
 | ||||
|             await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config) | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Octopush; | ||||
							
								
								
									
										50
									
								
								server/notification-providers/pushbullet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								server/notification-providers/pushbullet.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| const { DOWN, UP } = require("../../src/util"); | ||||
| 
 | ||||
| class Pushbullet extends NotificationProvider { | ||||
| 
 | ||||
|     name = "pushbullet"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             let pushbulletUrl = "https://api.pushbullet.com/v2/pushes"; | ||||
|             let config = { | ||||
|                 headers: { | ||||
|                     "Access-Token": notification.pushbulletAccessToken, | ||||
|                     "Content-Type": "application/json" | ||||
|                 } | ||||
|             }; | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let testdata = { | ||||
|                     "type": "note", | ||||
|                     "title": "Uptime Kuma Alert", | ||||
|                     "body": "Testing Successful.", | ||||
|                 } | ||||
|                 await axios.post(pushbulletUrl, testdata, config) | ||||
|             } else if (heartbeatJSON["status"] == DOWN) { | ||||
|                 let downdata = { | ||||
|                     "type": "note", | ||||
|                     "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                     "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                 } | ||||
|                 await axios.post(pushbulletUrl, downdata, config) | ||||
|             } else if (heartbeatJSON["status"] == UP) { | ||||
|                 let updata = { | ||||
|                     "type": "note", | ||||
|                     "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                     "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                 } | ||||
|                 await axios.post(pushbulletUrl, updata, config) | ||||
|             } | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Pushbullet; | ||||
							
								
								
									
										49
									
								
								server/notification-providers/pushover.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								server/notification-providers/pushover.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Pushover extends NotificationProvider { | ||||
| 
 | ||||
|     name = "pushover"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         let pushoverlink = "https://api.pushover.net/1/messages.json" | ||||
| 
 | ||||
|         try { | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let data = { | ||||
|                     "message": "<b>Uptime Kuma Pushover testing successful.</b>", | ||||
|                     "user": notification.pushoveruserkey, | ||||
|                     "token": notification.pushoverapptoken, | ||||
|                     "sound": notification.pushoversounds, | ||||
|                     "priority": notification.pushoverpriority, | ||||
|                     "title": notification.pushovertitle, | ||||
|                     "retry": "30", | ||||
|                     "expire": "3600", | ||||
|                     "html": 1, | ||||
|                 } | ||||
|                 await axios.post(pushoverlink, data) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             let data = { | ||||
|                 "message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg + "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"], | ||||
|                 "user": notification.pushoveruserkey, | ||||
|                 "token": notification.pushoverapptoken, | ||||
|                 "sound": notification.pushoversounds, | ||||
|                 "priority": notification.pushoverpriority, | ||||
|                 "title": notification.pushovertitle, | ||||
|                 "retry": "30", | ||||
|                 "expire": "3600", | ||||
|                 "html": 1, | ||||
|             } | ||||
|             await axios.post(pushoverlink, data) | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Pushover; | ||||
							
								
								
									
										30
									
								
								server/notification-providers/pushy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								server/notification-providers/pushy.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Pushy extends NotificationProvider { | ||||
| 
 | ||||
|     name = "pushy"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, { | ||||
|                 "to": notification.pushyToken, | ||||
|                 "data": { | ||||
|                     "message": "Uptime-Kuma" | ||||
|                 }, | ||||
|                 "notification": { | ||||
|                     "body": msg, | ||||
|                     "badge": 1, | ||||
|                     "sound": "ping.aiff" | ||||
|                 } | ||||
|             }) | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Pushy; | ||||
							
								
								
									
										46
									
								
								server/notification-providers/rocket-chat.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								server/notification-providers/rocket-chat.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class RocketChat extends NotificationProvider { | ||||
| 
 | ||||
|     name = "rocket.chat"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         try { | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let data = { | ||||
|                     "text": "Uptime Kuma Rocket.chat testing successful.", | ||||
|                     "channel": notification.rocketchannel, | ||||
|                     "username": notification.rocketusername, | ||||
|                     "icon_emoji": notification.rocketiconemo, | ||||
|                 } | ||||
|                 await axios.post(notification.rocketwebhookURL, data) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             const time = heartbeatJSON["time"]; | ||||
|             let data = { | ||||
|                 "text": "Uptime Kuma Alert", | ||||
|                 "channel": notification.rocketchannel, | ||||
|                 "username": notification.rocketusername, | ||||
|                 "icon_emoji": notification.rocketiconemo, | ||||
|                 "attachments": [ | ||||
|                     { | ||||
|                         "title": "Uptime Kuma Alert *Time (UTC)*\n" + time, | ||||
|                         "title_link": notification.rocketbutton, | ||||
|                         "text": "*Message*\n" + msg, | ||||
|                         "color": "#32cd32" | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|             await axios.post(notification.rocketwebhookURL, data) | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = RocketChat; | ||||
							
								
								
									
										27
									
								
								server/notification-providers/signal.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								server/notification-providers/signal.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Signal extends NotificationProvider { | ||||
| 
 | ||||
|     name = "signal"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             let data = { | ||||
|                 "message": msg, | ||||
|                 "number": notification.signalNumber, | ||||
|                 "recipients": notification.signalRecipients.replace(/\s/g, "").split(","), | ||||
|             }; | ||||
|             let config = {}; | ||||
| 
 | ||||
|             await axios.post(notification.signalURL, data, config) | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Signal; | ||||
							
								
								
									
										70
									
								
								server/notification-providers/slack.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								server/notification-providers/slack.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Slack extends NotificationProvider { | ||||
| 
 | ||||
|     name = "slack"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
|         try { | ||||
|             if (heartbeatJSON == null) { | ||||
|                 let data = { | ||||
|                     "text": "Uptime Kuma Slack testing successful.", | ||||
|                     "channel": notification.slackchannel, | ||||
|                     "username": notification.slackusername, | ||||
|                     "icon_emoji": notification.slackiconemo, | ||||
|                 } | ||||
|                 await axios.post(notification.slackwebhookURL, data) | ||||
|                 return okMsg; | ||||
|             } | ||||
| 
 | ||||
|             const time = heartbeatJSON["time"]; | ||||
|             let data = { | ||||
|                 "text": "Uptime Kuma Alert", | ||||
|                 "channel": notification.slackchannel, | ||||
|                 "username": notification.slackusername, | ||||
|                 "icon_emoji": notification.slackiconemo, | ||||
|                 "blocks": [{ | ||||
|                     "type": "header", | ||||
|                     "text": { | ||||
|                         "type": "plain_text", | ||||
|                         "text": "Uptime Kuma Alert", | ||||
|                     }, | ||||
|                 }, | ||||
|                 { | ||||
|                     "type": "section", | ||||
|                     "fields": [{ | ||||
|                         "type": "mrkdwn", | ||||
|                         "text": "*Message*\n" + msg, | ||||
|                     }, | ||||
|                     { | ||||
|                         "type": "mrkdwn", | ||||
|                         "text": "*Time (UTC)*\n" + time, | ||||
|                     }], | ||||
|                 }, | ||||
|                 { | ||||
|                     "type": "actions", | ||||
|                     "elements": [ | ||||
|                         { | ||||
|                             "type": "button", | ||||
|                             "text": { | ||||
|                                 "type": "plain_text", | ||||
|                                 "text": "Visit Uptime Kuma", | ||||
|                             }, | ||||
|                             "value": "Uptime-Kuma", | ||||
|                             "url": notification.slackbutton || "https://github.com/louislam/uptime-kuma", | ||||
|                         }, | ||||
|                     ], | ||||
|                 }], | ||||
|             } | ||||
|             await axios.post(notification.slackwebhookURL, data) | ||||
|             return okMsg; | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Slack; | ||||
							
								
								
									
										43
									
								
								server/notification-providers/smtp.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								server/notification-providers/smtp.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| const nodemailer = require("nodemailer"); | ||||
| const NotificationProvider = require("./notification-provider"); | ||||
| 
 | ||||
| class SMTP extends NotificationProvider { | ||||
| 
 | ||||
|     name = "smtp"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
| 
 | ||||
|         const config = { | ||||
|             host: notification.smtpHost, | ||||
|             port: notification.smtpPort, | ||||
|             secure: notification.smtpSecure, | ||||
|         }; | ||||
| 
 | ||||
|         // Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
 | ||||
|         if (notification.smtpUsername || notification.smtpPassword) { | ||||
|             config.auth = { | ||||
|                 user: notification.smtpUsername, | ||||
|                 pass: notification.smtpPassword, | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         let transporter = nodemailer.createTransport(config); | ||||
| 
 | ||||
|         let bodyTextContent = msg; | ||||
|         if (heartbeatJSON) { | ||||
|             bodyTextContent = `${msg}\nTime (UTC): ${heartbeatJSON["time"]}`; | ||||
|         } | ||||
| 
 | ||||
|         // send mail with defined transport object
 | ||||
|         await transporter.sendMail({ | ||||
|             from: `"Uptime Kuma" <${notification.smtpFrom}>`, | ||||
|             to: notification.smtpTo, | ||||
|             subject: msg, | ||||
|             text: bodyTextContent, | ||||
|         }); | ||||
| 
 | ||||
|         return "Sent Successfully."; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = SMTP; | ||||
							
								
								
									
										27
									
								
								server/notification-providers/telegram.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								server/notification-providers/telegram.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| 
 | ||||
| class Telegram extends NotificationProvider { | ||||
| 
 | ||||
|     name = "telegram"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, { | ||||
|                 params: { | ||||
|                     chat_id: notification.telegramChatID, | ||||
|                     text: msg, | ||||
|                 }, | ||||
|             }) | ||||
|             return okMsg; | ||||
| 
 | ||||
|         } catch (error) { | ||||
|             let msg = (error.response.data.description) ? error.response.data.description : "Error without description" | ||||
|             throw new Error(msg) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = Telegram; | ||||
							
								
								
									
										44
									
								
								server/notification-providers/webhook.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								server/notification-providers/webhook.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| const NotificationProvider = require("./notification-provider"); | ||||
| const axios = require("axios"); | ||||
| const FormData = require("form-data"); | ||||
| 
 | ||||
| class Webhook extends NotificationProvider { | ||||
| 
 | ||||
|     name = "webhook"; | ||||
| 
 | ||||
|     async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         try { | ||||
|             let data = { | ||||
|                 heartbeat: heartbeatJSON, | ||||
|                 monitor: monitorJSON, | ||||
|                 msg, | ||||
|             }; | ||||
|             let finalData; | ||||
|             let config = {}; | ||||
| 
 | ||||
|             if (notification.webhookContentType === "form-data") { | ||||
|                 finalData = new FormData(); | ||||
|                 finalData.append("data", JSON.stringify(data)); | ||||
| 
 | ||||
|                 config = { | ||||
|                     headers: finalData.getHeaders(), | ||||
|                 } | ||||
| 
 | ||||
|             } else { | ||||
|                 finalData = data; | ||||
|             } | ||||
| 
 | ||||
|             await axios.post(notification.webhookURL, finalData, config) | ||||
|             return okMsg; | ||||
| 
 | ||||
|         } catch (error) { | ||||
|             this.throwGeneralAxiosError(error) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| module.exports = Webhook; | ||||
|  | @ -1,602 +1,75 @@ | |||
| const axios = require("axios"); | ||||
| const { R } = require("redbean-node"); | ||||
| const FormData = require("form-data"); | ||||
| const nodemailer = require("nodemailer"); | ||||
| const child_process = require("child_process"); | ||||
| 
 | ||||
| const { UP, DOWN } = require("../src/util"); | ||||
| const Apprise = require("./notification-providers/apprise"); | ||||
| const Discord = require("./notification-providers/discord"); | ||||
| const Gotify = require("./notification-providers/gotify"); | ||||
| const Line = require("./notification-providers/line"); | ||||
| const LunaSea = require("./notification-providers/lunasea"); | ||||
| const Mattermost = require("./notification-providers/mattermost"); | ||||
| const Octopush = require("./notification-providers/octopush"); | ||||
| const Pushbullet = require("./notification-providers/pushbullet"); | ||||
| const Pushover = require("./notification-providers/pushover"); | ||||
| const Pushy = require("./notification-providers/pushy"); | ||||
| const RocketChat = require("./notification-providers/rocket-chat"); | ||||
| const Signal = require("./notification-providers/signal"); | ||||
| const Slack = require("./notification-providers/slack"); | ||||
| const SMTP = require("./notification-providers/smtp"); | ||||
| const Telegram = require("./notification-providers/telegram"); | ||||
| const Webhook = require("./notification-providers/webhook"); | ||||
| 
 | ||||
| class Notification { | ||||
| 
 | ||||
|     providerList = {}; | ||||
| 
 | ||||
|     static init() { | ||||
|         console.log("Prepare Notification Providers"); | ||||
| 
 | ||||
|         this.providerList = {}; | ||||
| 
 | ||||
|         const list = [ | ||||
|             new Apprise(), | ||||
|             new Discord(), | ||||
|             new Gotify(), | ||||
|             new Line(), | ||||
|             new LunaSea(), | ||||
|             new Mattermost(), | ||||
|             new Octopush(), | ||||
|             new Pushbullet(), | ||||
|             new Pushover(), | ||||
|             new Pushy(), | ||||
|             new RocketChat(), | ||||
|             new Signal(), | ||||
|             new Slack(), | ||||
|             new SMTP(), | ||||
|             new Telegram(), | ||||
|             new Webhook(), | ||||
|         ]; | ||||
| 
 | ||||
|         for (let item of list) { | ||||
|             if (! item.name) { | ||||
|                 throw new Error("Notification provider without name"); | ||||
|             } | ||||
| 
 | ||||
|             if (this.providerList[item.name]) { | ||||
|                 throw new Error("Duplicate notification provider name"); | ||||
|             } | ||||
|             this.providerList[item.name] = item; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * | ||||
|      * @param notification | ||||
|      * @param msg | ||||
|      * @param monitorJSON | ||||
|      * @param heartbeatJSON | ||||
|      * @param notification : BeanModel | ||||
|      * @param msg : string General Message | ||||
|      * @param monitorJSON : object Monitor details (For Up/Down only) | ||||
|      * @param heartbeatJSON : object Heartbeat details (For Up/Down only) | ||||
|      * @returns {Promise<string>} Successful msg | ||||
|      * Throw Error with fail msg | ||||
|      */ | ||||
|     static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { | ||||
|         let okMsg = "Sent Successfully. "; | ||||
| 
 | ||||
|         if (notification.type === "telegram") { | ||||
|             try { | ||||
|                 await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, { | ||||
|                     params: { | ||||
|                         chat_id: notification.telegramChatID, | ||||
|                         text: msg, | ||||
|                     }, | ||||
|                 }) | ||||
|                 return okMsg; | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 let msg = (error.response.data.description) ? error.response.data.description : "Error without description" | ||||
|                 throw new Error(msg) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "gotify") { | ||||
|             try { | ||||
|                 if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) { | ||||
|                     notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1); | ||||
|                 } | ||||
|                 await axios.post(`${notification.gotifyserverurl}/message?token=${notification.gotifyapplicationToken}`, { | ||||
|                     "message": msg, | ||||
|                     "priority": notification.gotifyPriority || 8, | ||||
|                     "title": "Uptime-Kuma", | ||||
|                 }) | ||||
| 
 | ||||
|                 return okMsg; | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "webhook") { | ||||
|             try { | ||||
|                 let data = { | ||||
|                     heartbeat: heartbeatJSON, | ||||
|                     monitor: monitorJSON, | ||||
|                     msg, | ||||
|                 }; | ||||
|                 let finalData; | ||||
|                 let config = {}; | ||||
| 
 | ||||
|                 if (notification.webhookContentType === "form-data") { | ||||
|                     finalData = new FormData(); | ||||
|                     finalData.append("data", JSON.stringify(data)); | ||||
| 
 | ||||
|                     config = { | ||||
|                         headers: finalData.getHeaders(), | ||||
|                     } | ||||
| 
 | ||||
|                 } else { | ||||
|                     finalData = data; | ||||
|                 } | ||||
| 
 | ||||
|                 await axios.post(notification.webhookURL, finalData, config) | ||||
|                 return okMsg; | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "smtp") { | ||||
|             return await Notification.smtp(notification, msg, heartbeatJSON) | ||||
| 
 | ||||
|         } else if (notification.type === "discord") { | ||||
|             try { | ||||
|                 const discordDisplayName = notification.discordUsername || "Uptime Kuma"; | ||||
| 
 | ||||
|                 // If heartbeatJSON is null, assume we're testing.
 | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let discordtestdata = { | ||||
|                         username: discordDisplayName, | ||||
|                         content: msg, | ||||
|                     } | ||||
|                     await axios.post(notification.discordWebhookUrl, discordtestdata) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 let url; | ||||
| 
 | ||||
|                 if (monitorJSON["type"] === "port") { | ||||
|                     url = monitorJSON["hostname"]; | ||||
|                     if (monitorJSON["port"]) { | ||||
|                         url += ":" + monitorJSON["port"]; | ||||
|                     } | ||||
| 
 | ||||
|                 } else { | ||||
|                     url = monitorJSON["url"]; | ||||
|                 } | ||||
| 
 | ||||
|                 // If heartbeatJSON is not null, we go into the normal alerting loop.
 | ||||
|                 if (heartbeatJSON["status"] == DOWN) { | ||||
|                     let discorddowndata = { | ||||
|                         username: discordDisplayName, | ||||
|                         embeds: [{ | ||||
|                             title: "❌ Your service " + monitorJSON["name"] + " went down. ❌", | ||||
|                             color: 16711680, | ||||
|                             timestamp: heartbeatJSON["time"], | ||||
|                             fields: [ | ||||
|                                 { | ||||
|                                     name: "Service Name", | ||||
|                                     value: monitorJSON["name"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     name: "Service URL", | ||||
|                                     value: url, | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     name: "Time (UTC)", | ||||
|                                     value: heartbeatJSON["time"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     name: "Error", | ||||
|                                     value: heartbeatJSON["msg"], | ||||
|                                 }, | ||||
|                             ], | ||||
|                         }], | ||||
|                     } | ||||
|                     await axios.post(notification.discordWebhookUrl, discorddowndata) | ||||
|                     return okMsg; | ||||
| 
 | ||||
|                 } else if (heartbeatJSON["status"] == UP) { | ||||
|                     let discordupdata = { | ||||
|                         username: discordDisplayName, | ||||
|                         embeds: [{ | ||||
|                             title: "✅ Your service " + monitorJSON["name"] + " is up! ✅", | ||||
|                             color: 65280, | ||||
|                             timestamp: heartbeatJSON["time"], | ||||
|                             fields: [ | ||||
|                                 { | ||||
|                                     name: "Service Name", | ||||
|                                     value: monitorJSON["name"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     name: "Service URL", | ||||
|                                     value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url, | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     name: "Time (UTC)", | ||||
|                                     value: heartbeatJSON["time"], | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     name: "Ping", | ||||
|                                     value: heartbeatJSON["ping"] + "ms", | ||||
|                                 }, | ||||
|                             ], | ||||
|                         }], | ||||
|                     } | ||||
|                     await axios.post(notification.discordWebhookUrl, discordupdata) | ||||
|                     return okMsg; | ||||
|                 } | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "signal") { | ||||
|             try { | ||||
|                 let data = { | ||||
|                     "message": msg, | ||||
|                     "number": notification.signalNumber, | ||||
|                     "recipients": notification.signalRecipients.replace(/\s/g, "").split(","), | ||||
|                 }; | ||||
|                 let config = {}; | ||||
| 
 | ||||
|                 await axios.post(notification.signalURL, data, config) | ||||
|                 return okMsg; | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "pushy") { | ||||
|             try { | ||||
|                 await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, { | ||||
|                     "to": notification.pushyToken, | ||||
|                     "data": { | ||||
|                         "message": "Uptime-Kuma" | ||||
|                     }, | ||||
|                     "notification": { | ||||
|                         "body": msg, | ||||
|                         "badge": 1, | ||||
|                         "sound": "ping.aiff" | ||||
|                     } | ||||
|                 }) | ||||
|                 return true; | ||||
|             } catch (error) { | ||||
|                 console.log(error) | ||||
|                 return false; | ||||
|             } | ||||
|         } else if (notification.type === "octopush") { | ||||
|             try { | ||||
|                 let config = { | ||||
|                     headers: { | ||||
|                         "api-key": notification.octopushAPIKey, | ||||
|                         "api-login": notification.octopushLogin, | ||||
|                         "cache-control": "no-cache" | ||||
|                     } | ||||
|                 }; | ||||
|                 let data = { | ||||
|                     "recipients": [ | ||||
|                         { | ||||
|                             "phone_number": notification.octopushPhoneNumber | ||||
|                         } | ||||
|                     ], | ||||
|                     //octopush not supporting non ascii char
 | ||||
|                     "text": msg.replace(/[^\x00-\x7F]/g, ""), | ||||
|                     "type": notification.octopushSMSType, | ||||
|                     "purpose": "alert", | ||||
|                     "sender": notification.octopushSenderName | ||||
|                 }; | ||||
| 
 | ||||
|                 await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config) | ||||
|                 return true; | ||||
|             } catch (error) { | ||||
|                 console.log(error) | ||||
|                 return false; | ||||
|             } | ||||
|         } else if (notification.type === "slack") { | ||||
|             try { | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let data = { | ||||
|                         "text": "Uptime Kuma Slack testing successful.", | ||||
|                         "channel": notification.slackchannel, | ||||
|                         "username": notification.slackusername, | ||||
|                         "icon_emoji": notification.slackiconemo, | ||||
|                     } | ||||
|                     await axios.post(notification.slackwebhookURL, data) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 const time = heartbeatJSON["time"]; | ||||
|                 let data = { | ||||
|                     "text": "Uptime Kuma Alert", | ||||
|                     "channel": notification.slackchannel, | ||||
|                     "username": notification.slackusername, | ||||
|                     "icon_emoji": notification.slackiconemo, | ||||
|                     "blocks": [{ | ||||
|                         "type": "header", | ||||
|                         "text": { | ||||
|                             "type": "plain_text", | ||||
|                             "text": "Uptime Kuma Alert", | ||||
|                         }, | ||||
|                     }, | ||||
|                     { | ||||
|                         "type": "section", | ||||
|                         "fields": [{ | ||||
|                             "type": "mrkdwn", | ||||
|                             "text": "*Message*\n" + msg, | ||||
|                         }, | ||||
|                         { | ||||
|                             "type": "mrkdwn", | ||||
|                             "text": "*Time (UTC)*\n" + time, | ||||
|                         }], | ||||
|                     }, | ||||
|                     { | ||||
|                         "type": "actions", | ||||
|                         "elements": [ | ||||
|                             { | ||||
|                                 "type": "button", | ||||
|                                 "text": { | ||||
|                                     "type": "plain_text", | ||||
|                                     "text": "Visit Uptime Kuma", | ||||
|                                 }, | ||||
|                                 "value": "Uptime-Kuma", | ||||
|                                 "url": notification.slackbutton || "https://github.com/louislam/uptime-kuma", | ||||
|                             }, | ||||
|                         ], | ||||
|                     }], | ||||
|                 } | ||||
|                 await axios.post(notification.slackwebhookURL, data) | ||||
|                 return okMsg; | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "rocket.chat") { | ||||
|             try { | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let data = { | ||||
|                         "text": "Uptime Kuma Rocket.chat testing successful.", | ||||
|                         "channel": notification.rocketchannel, | ||||
|                         "username": notification.rocketusername, | ||||
|                         "icon_emoji": notification.rocketiconemo, | ||||
|                     } | ||||
|                     await axios.post(notification.rocketwebhookURL, data) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 const time = heartbeatJSON["time"]; | ||||
|                 let data = { | ||||
|                     "text": "Uptime Kuma Alert", | ||||
|                     "channel": notification.rocketchannel, | ||||
|                     "username": notification.rocketusername, | ||||
|                     "icon_emoji": notification.rocketiconemo, | ||||
|                     "attachments": [ | ||||
|                         { | ||||
|                             "title": "Uptime Kuma Alert *Time (UTC)*\n" + time, | ||||
|                             "title_link": notification.rocketbutton, | ||||
|                             "text": "*Message*\n" + msg, | ||||
|                             "color": "#32cd32" | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|                 await axios.post(notification.rocketwebhookURL, data) | ||||
|                 return okMsg; | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "mattermost") { | ||||
|             try { | ||||
|                 const mattermostUserName = notification.mattermostusername || "Uptime Kuma"; | ||||
|                 // If heartbeatJSON is null, assume we're testing.
 | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let mattermostTestData = { | ||||
|                         username: mattermostUserName, | ||||
|                         text: msg, | ||||
|                     } | ||||
|                     await axios.post(notification.mattermostWebhookUrl, mattermostTestData) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 const mattermostChannel = notification.mattermostchannel; | ||||
|                 const mattermostIconEmoji = notification.mattermosticonemo; | ||||
|                 const mattermostIconUrl = notification.mattermosticonurl; | ||||
| 
 | ||||
|                 if (heartbeatJSON["status"] == DOWN) { | ||||
|                     let mattermostdowndata = { | ||||
|                         username: mattermostUserName, | ||||
|                         text: "Uptime Kuma Alert", | ||||
|                         channel: mattermostChannel, | ||||
|                         icon_emoji: mattermostIconEmoji, | ||||
|                         icon_url: mattermostIconUrl, | ||||
|                         attachments: [ | ||||
|                             { | ||||
|                                 fallback: | ||||
|                                     "Your " + | ||||
|                                     monitorJSON["name"] + | ||||
|                                     " service went down.", | ||||
|                                 color: "#FF0000", | ||||
|                                 title: | ||||
|                                     "❌ " + | ||||
|                                     monitorJSON["name"] + | ||||
|                                     " service went down. ❌", | ||||
|                                 title_link: monitorJSON["url"], | ||||
|                                 fields: [ | ||||
|                                     { | ||||
|                                         short: true, | ||||
|                                         title: "Service Name", | ||||
|                                         value: monitorJSON["name"], | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         short: true, | ||||
|                                         title: "Time (UTC)", | ||||
|                                         value: heartbeatJSON["time"], | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         short: false, | ||||
|                                         title: "Error", | ||||
|                                         value: heartbeatJSON["msg"], | ||||
|                                     }, | ||||
|                                 ], | ||||
|                             }, | ||||
|                         ], | ||||
|                     }; | ||||
|                     await axios.post( | ||||
|                         notification.mattermostWebhookUrl, | ||||
|                         mattermostdowndata | ||||
|                     ); | ||||
|                     return okMsg; | ||||
|                 } else if (heartbeatJSON["status"] == UP) { | ||||
|                     let mattermostupdata = { | ||||
|                         username: mattermostUserName, | ||||
|                         text: "Uptime Kuma Alert", | ||||
|                         channel: mattermostChannel, | ||||
|                         icon_emoji: mattermostIconEmoji, | ||||
|                         icon_url: mattermostIconUrl, | ||||
|                         attachments: [ | ||||
|                             { | ||||
|                                 fallback: | ||||
|                                     "Your " + | ||||
|                                     monitorJSON["name"] + | ||||
|                                     " service went up!", | ||||
|                                 color: "#32CD32", | ||||
|                                 title: | ||||
|                                     "✅ " + | ||||
|                                     monitorJSON["name"] + | ||||
|                                     " service went up! ✅", | ||||
|                                 title_link: monitorJSON["url"], | ||||
|                                 fields: [ | ||||
|                                     { | ||||
|                                         short: true, | ||||
|                                         title: "Service Name", | ||||
|                                         value: monitorJSON["name"], | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         short: true, | ||||
|                                         title: "Time (UTC)", | ||||
|                                         value: heartbeatJSON["time"], | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         short: false, | ||||
|                                         title: "Ping", | ||||
|                                         value: heartbeatJSON["ping"] + "ms", | ||||
|                                     }, | ||||
|                                 ], | ||||
|                             }, | ||||
|                         ], | ||||
|                     }; | ||||
|                     await axios.post( | ||||
|                         notification.mattermostWebhookUrl, | ||||
|                         mattermostupdata | ||||
|                     ); | ||||
|                     return okMsg; | ||||
|                 } | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error); | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "pushover") { | ||||
|             let pushoverlink = "https://api.pushover.net/1/messages.json" | ||||
|             try { | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let data = { | ||||
|                         "message": "<b>Uptime Kuma Pushover testing successful.</b>", | ||||
|                         "user": notification.pushoveruserkey, | ||||
|                         "token": notification.pushoverapptoken, | ||||
|                         "sound": notification.pushoversounds, | ||||
|                         "priority": notification.pushoverpriority, | ||||
|                         "title": notification.pushovertitle, | ||||
|                         "retry": "30", | ||||
|                         "expire": "3600", | ||||
|                         "html": 1, | ||||
|                     } | ||||
|                     await axios.post(pushoverlink, data) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 let data = { | ||||
|                     "message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg + "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"], | ||||
|                     "user": notification.pushoveruserkey, | ||||
|                     "token": notification.pushoverapptoken, | ||||
|                     "sound": notification.pushoversounds, | ||||
|                     "priority": notification.pushoverpriority, | ||||
|                     "title": notification.pushovertitle, | ||||
|                     "retry": "30", | ||||
|                     "expire": "3600", | ||||
|                     "html": 1, | ||||
|                 } | ||||
|                 await axios.post(pushoverlink, data) | ||||
|                 return okMsg; | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "apprise") { | ||||
| 
 | ||||
|             return Notification.apprise(notification, msg) | ||||
| 
 | ||||
|         } else if (notification.type === "lunasea") { | ||||
|             let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice | ||||
| 
 | ||||
|             try { | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let testdata = { | ||||
|                         "title": "Uptime Kuma Alert", | ||||
|                         "body": "Testing Successful.", | ||||
|                     } | ||||
|                     await axios.post(lunaseadevice, testdata) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 if (heartbeatJSON["status"] == DOWN) { | ||||
|                     let downdata = { | ||||
|                         "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                         "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                     } | ||||
|                     await axios.post(lunaseadevice, downdata) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|                 if (heartbeatJSON["status"] == UP) { | ||||
|                     let updata = { | ||||
|                         "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                         "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                     } | ||||
|                     await axios.post(lunaseadevice, updata) | ||||
|                     return okMsg; | ||||
|                 } | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
| 
 | ||||
|         } else if (notification.type === "pushbullet") { | ||||
|             try { | ||||
|                 let pushbulletUrl = "https://api.pushbullet.com/v2/pushes"; | ||||
|                 let config = { | ||||
|                     headers: { | ||||
|                         "Access-Token": notification.pushbulletAccessToken, | ||||
|                         "Content-Type": "application/json" | ||||
|                     } | ||||
|                 }; | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let testdata = { | ||||
|                         "type": "note", | ||||
|                         "title": "Uptime Kuma Alert", | ||||
|                         "body": "Testing Successful.", | ||||
|                     } | ||||
|                     await axios.post(pushbulletUrl, testdata, config) | ||||
|                 } else if (heartbeatJSON["status"] == DOWN) { | ||||
|                     let downdata = { | ||||
|                         "type": "note", | ||||
|                         "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                         "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                     } | ||||
|                     await axios.post(pushbulletUrl, downdata, config) | ||||
|                 } else if (heartbeatJSON["status"] == UP) { | ||||
|                     let updata = { | ||||
|                         "type": "note", | ||||
|                         "title": "UptimeKuma Alert: " + monitorJSON["name"], | ||||
|                         "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], | ||||
|                     } | ||||
|                     await axios.post(pushbulletUrl, updata, config) | ||||
|                 } | ||||
|                 return okMsg; | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
|         } else if (notification.type === "line") { | ||||
|             try { | ||||
|                 let lineAPIUrl = "https://api.line.me/v2/bot/message/push"; | ||||
|                 let config = { | ||||
|                     headers: { | ||||
|                         "Content-Type": "application/json", | ||||
|                         "Authorization": "Bearer " + notification.lineChannelAccessToken | ||||
|                     } | ||||
|                 }; | ||||
|                 if (heartbeatJSON == null) { | ||||
|                     let testMessage = { | ||||
|                         "to": notification.lineUserID, | ||||
|                         "messages": [ | ||||
|                             { | ||||
|                                 "type": "text", | ||||
|                                 "text": "Test Successful!" | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                     await axios.post(lineAPIUrl, testMessage, config) | ||||
|                 } else if (heartbeatJSON["status"] == DOWN) { | ||||
|                     let downMessage = { | ||||
|                         "to": notification.lineUserID, | ||||
|                         "messages": [ | ||||
|                             { | ||||
|                                 "type": "text", | ||||
|                                 "text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                     await axios.post(lineAPIUrl, downMessage, config) | ||||
|                 } else if (heartbeatJSON["status"] == UP) { | ||||
|                     let upMessage = { | ||||
|                         "to": notification.lineUserID, | ||||
|                         "messages": [ | ||||
|                             { | ||||
|                                 "type": "text", | ||||
|                                 "text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] | ||||
|                             } | ||||
|                         ] | ||||
|                     } | ||||
|                     await axios.post(lineAPIUrl, upMessage, config) | ||||
|                 } | ||||
|                 return okMsg; | ||||
|             } catch (error) { | ||||
|                 throwGeneralAxiosError(error) | ||||
|             } | ||||
|         if (this.providerList[notification.type]) { | ||||
|             return this.providerList[notification.type].send(notification, msg, monitorJSON, heartbeatJSON); | ||||
|         } else { | ||||
|             throw new Error("Notification type is not supported") | ||||
|             throw new Error("Notification type is not supported"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -636,57 +109,6 @@ class Notification { | |||
|         await R.trash(bean) | ||||
|     } | ||||
| 
 | ||||
|     static async smtp(notification, msg, heartbeatJSON = null) { | ||||
| 
 | ||||
|         const config = { | ||||
|             host: notification.smtpHost, | ||||
|             port: notification.smtpPort, | ||||
|             secure: notification.smtpSecure, | ||||
|         }; | ||||
| 
 | ||||
|         // Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
 | ||||
|         if (notification.smtpUsername || notification.smtpPassword) { | ||||
|             config.auth = { | ||||
|                 user: notification.smtpUsername, | ||||
|                 pass: notification.smtpPassword, | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         let transporter = nodemailer.createTransport(config); | ||||
| 
 | ||||
|         let bodyTextContent = msg; | ||||
|         if(heartbeatJSON) { | ||||
|             bodyTextContent = `${msg}\nTime (UTC): ${heartbeatJSON["time"]}`; | ||||
|         } | ||||
| 
 | ||||
|         // send mail with defined transport object
 | ||||
|         await transporter.sendMail({ | ||||
|             from: `"Uptime Kuma" <${notification.smtpFrom}>`, | ||||
|             to: notification.smtpTo, | ||||
|             subject: msg, | ||||
|             text: bodyTextContent, | ||||
|         }); | ||||
| 
 | ||||
|         return "Sent Successfully."; | ||||
|     } | ||||
| 
 | ||||
|     static async apprise(notification, msg) { | ||||
|         let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL]) | ||||
| 
 | ||||
|         let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found"; | ||||
| 
 | ||||
|         if (output) { | ||||
| 
 | ||||
|             if (! output.includes("ERROR")) { | ||||
|                 return "Sent Successfully"; | ||||
|             } | ||||
| 
 | ||||
|             throw new Error(output) | ||||
|         } else { | ||||
|             return "" | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static checkApprise() { | ||||
|         let commandExistsSync = require("command-exists").sync; | ||||
|         let exists = commandExistsSync("apprise"); | ||||
|  | @ -695,20 +117,6 @@ class Notification { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| function throwGeneralAxiosError(error) { | ||||
|     let msg = "Error: " + error + " "; | ||||
| 
 | ||||
|     if (error.response && error.response.data) { | ||||
|         if (typeof error.response.data === "string") { | ||||
|             msg += error.response.data; | ||||
|         } else { | ||||
|             msg += JSON.stringify(error.response.data) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     throw new Error(msg) | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|     Notification, | ||||
| } | ||||
|  |  | |||
|  | @ -27,8 +27,11 @@ debug("Importing Monitor"); | |||
| const Monitor = require("./model/monitor"); | ||||
| debug("Importing Settings"); | ||||
| const { getSettings, setSettings, setting, initJWTSecret } = require("./util-server"); | ||||
| 
 | ||||
| debug("Importing Notification"); | ||||
| const { Notification } = require("./notification"); | ||||
| Notification.init(); | ||||
| 
 | ||||
| debug("Importing Database"); | ||||
| const Database = require("./database"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -137,7 +137,6 @@ export default { | |||
| 
 | ||||
|         if (! Number.isInteger(actualWidth)) { | ||||
|             this.beatWidth = Math.round(actualWidth) / window.devicePixelRatio; | ||||
|             console.log(this.beatWidth); | ||||
|         } | ||||
| 
 | ||||
|         if (! Number.isInteger(actualMargin)) { | ||||
|  |  | |||
|  | @ -1,11 +1,7 @@ | |||
| <template> | ||||
|     <div class="input-group mb-3"> | ||||
|         <!-- | ||||
|         Hack - Disable Chrome save password | ||||
|         readonly + onfocus | ||||
|         https://stackoverflow.com/questions/41217019/how-to-prevent-a-browser-from-storing-passwords | ||||
|        --> | ||||
|         <input | ||||
|             ref="input" | ||||
|             v-model="model" | ||||
|             :type="visibility" | ||||
|             class="form-control" | ||||
|  | @ -13,8 +9,7 @@ | |||
|             :maxlength="maxlength" | ||||
|             :autocomplete="autocomplete" | ||||
|             :required="required" | ||||
|             :readonly="isReadOnly" | ||||
|             @focus="removeReadOnly" | ||||
|             :readonly="readonly" | ||||
|         > | ||||
| 
 | ||||
|         <a v-if="visibility == 'password'" class="btn btn-outline-primary" @click="showInput()"> | ||||
|  | @ -42,20 +37,20 @@ export default { | |||
|             default: 255 | ||||
|         }, | ||||
|         autocomplete: { | ||||
|             type: Boolean, | ||||
|             type: String, | ||||
|             default: undefined, | ||||
|         }, | ||||
|         required: { | ||||
|             type: Boolean | ||||
|         }, | ||||
|         readonly: { | ||||
|             type: Boolean, | ||||
|             default: false, | ||||
|             type: String, | ||||
|             default: undefined, | ||||
|         }, | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             visibility: "password", | ||||
|             readOnlyValue: false, | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|  | @ -66,22 +61,10 @@ export default { | |||
|             set(value) { | ||||
|                 this.$emit("update:modelValue", value) | ||||
|             } | ||||
|         }, | ||||
|         isReadOnly() { | ||||
|             // Actually readonly from prop | ||||
|             if (this.readonly) { | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             // Hack - Disable Chrome save password | ||||
|             return this.readOnlyValue; | ||||
|         } | ||||
|     }, | ||||
|     created() { | ||||
|         // Hack - Disable Chrome save password | ||||
|         if (this.autocomplete) { | ||||
|             this.readOnlyValue = "readonly"; | ||||
|         } | ||||
| 
 | ||||
|     }, | ||||
|     methods: { | ||||
|         showInput() { | ||||
|  | @ -90,13 +73,6 @@ export default { | |||
|         hideInput() { | ||||
|             this.visibility = "password"; | ||||
|         }, | ||||
| 
 | ||||
|         // Hack - Disable Chrome save password | ||||
|         removeReadOnly() { | ||||
|             if (this.autocomplete) { | ||||
|                 this.readOnlyValue = false; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -37,44 +37,9 @@ | |||
|                             <input id="name" v-model="notification.name" type="text" class="form-control" required> | ||||
|                         </div> | ||||
| 
 | ||||
|                         <template v-if="notification.type === 'telegram'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="telegram-bot-token" class="form-label">Bot Token</label> | ||||
|                                 <HiddenInput id="telegram-bot-token" v-model="notification.telegramBotToken" :required="true" :readonly="true"></HiddenInput> | ||||
|                                 <div class="form-text"> | ||||
|                                     You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>. | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         <Telegram></Telegram> | ||||
| 
 | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="telegram-chat-id" class="form-label">Chat ID</label> | ||||
| 
 | ||||
|                                 <div class="input-group mb-3"> | ||||
|                                     <input id="telegram-chat-id" v-model="notification.telegramChatID" type="text" class="form-control" required> | ||||
|                                     <button v-if="notification.telegramBotToken" class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID"> | ||||
|                                         Auto Get | ||||
|                                     </button> | ||||
|                                 </div> | ||||
| 
 | ||||
|                                 <div class="form-text"> | ||||
|                                     Support Direct Chat / Group / Channel's Chat ID | ||||
| 
 | ||||
|                                     <p style="margin-top: 8px;"> | ||||
|                                         You can get your chat id by sending message to the bot and go to this url to view the chat_id: | ||||
|                                     </p> | ||||
| 
 | ||||
|                                     <p style="margin-top: 8px;"> | ||||
|                                         <template v-if="notification.telegramBotToken"> | ||||
|                                             <a :href="telegramGetUpdatesURL" target="_blank" style="word-break: break-word;">{{ telegramGetUpdatesURL }}</a> | ||||
|                                         </template> | ||||
| 
 | ||||
|                                         <template v-else> | ||||
|                                             {{ telegramGetUpdatesURL }} | ||||
|                                         </template> | ||||
|                                     </p> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </template> | ||||
|                         <!-- TODO: Convert all into vue components, but not an easy task.  --> | ||||
| 
 | ||||
|                         <template v-if="notification.type === 'webhook'"> | ||||
|                             <div class="mb-3"> | ||||
|  | @ -130,7 +95,7 @@ | |||
| 
 | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="password" class="form-label">Password</label> | ||||
|                                 <HiddenInput id="password" v-model="notification.smtpPassword" :required="true" autocomplete="false"></HiddenInput> | ||||
|                                 <HiddenInput id="password" v-model="notification.smtpPassword" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                             </div> | ||||
| 
 | ||||
|                             <div class="mb-3"> | ||||
|  | @ -195,7 +160,7 @@ | |||
|                         <template v-if="notification.type === 'gotify'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="gotify-application-token" class="form-label">Application Token</label> | ||||
|                                 <HiddenInput id="gotify-application-token" v-model="notification.gotifyapplicationToken" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="gotify-application-token" v-model="notification.gotifyapplicationToken" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                             </div> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="gotify-server-url" class="form-label">Server URL</label> | ||||
|  | @ -306,13 +271,13 @@ | |||
|                         <template v-if="notification.type === 'pushy'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="pushy-app-token" class="form-label">API_KEY</label> | ||||
|                                 <HiddenInput id="pushy-app-token" v-model="notification.pushyAPIKey" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="pushy-app-token" v-model="notification.pushyAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                             </div> | ||||
| 
 | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="pushy-user-key" class="form-label">USER_TOKEN</label> | ||||
|                                 <div class="input-group mb-3"> | ||||
|                                     <HiddenInput id="pushy-user-key" v-model="notification.pushyToken" :required="true"></HiddenInput> | ||||
|                                     <HiddenInput id="pushy-user-key" v-model="notification.pushyToken" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                             <p style="margin-top: 8px;"> | ||||
|  | @ -323,7 +288,7 @@ | |||
|                         <template v-if="notification.type === 'octopush'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="octopush-key" class="form-label">API KEY</label> | ||||
|                                 <HiddenInput id="octopush-key" v-model="notification.octopushAPIKey" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="octopush-key" v-model="notification.octopushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                                 <label for="octopush-login" class="form-label">API LOGIN</label> | ||||
|                                 <input id="octopush-login" v-model="notification.octopushLogin" type="text" class="form-control" required> | ||||
|                             </div> | ||||
|  | @ -354,9 +319,9 @@ | |||
|                         <template v-if="notification.type === 'pushover'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="pushover-user" class="form-label">User Key<span style="color: red;"><sup>*</sup></span></label> | ||||
|                                 <HiddenInput id="pushover-user" v-model="notification.pushoveruserkey" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="pushover-user" v-model="notification.pushoveruserkey" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                                 <label for="pushover-app-token" class="form-label">Application Token<span style="color: red;"><sup>*</sup></span></label> | ||||
|                                 <HiddenInput id="pushover-app-token" v-model="notification.pushoverapptoken" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="pushover-app-token" v-model="notification.pushoverapptoken" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                                 <label for="pushover-device" class="form-label">Device</label> | ||||
|                                 <input id="pushover-device" v-model="notification.pushoverdevice" type="text" class="form-control"> | ||||
|                                 <label for="pushover-device" class="form-label">Message Title</label> | ||||
|  | @ -442,7 +407,7 @@ | |||
|                         <template v-if="notification.type === 'pushbullet'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="pushbullet-access-token" class="form-label">Access Token</label> | ||||
|                                 <HiddenInput id="pushbullet-access-token" v-model="notification.pushbulletAccessToken" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="pushbullet-access-token" v-model="notification.pushbulletAccessToken" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                             </div> | ||||
| 
 | ||||
|                             <p style="margin-top: 8px;"> | ||||
|  | @ -453,7 +418,7 @@ | |||
|                         <template v-if="notification.type === 'line'"> | ||||
|                             <div class="mb-3"> | ||||
|                                 <label for="line-channel-access-token" class="form-label">Channel access token</label> | ||||
|                                 <HiddenInput id="line-channel-access-token" v-model="notification.lineChannelAccessToken" :required="true"></HiddenInput> | ||||
|                                 <HiddenInput id="line-channel-access-token" v-model="notification.lineChannelAccessToken" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|                             </div> | ||||
|                             <div class="form-text"> | ||||
|                                 Line Developers Console - <b>Basic Settings</b> | ||||
|  | @ -469,6 +434,8 @@ | |||
|                                 First access the <a href="https://developers.line.biz/console/" target="_blank">Line Developers Console</a>, create a provider and channel (Messaging API), then you can get the channel access token and user id from the above mentioned menu items. | ||||
|                             </div> | ||||
|                         </template> | ||||
| 
 | ||||
|                         <!-- DEPRECATED! Please create vue component in "./src/components/notifications/{notification name}.vue" --> | ||||
|                     </div> | ||||
|                     <div class="modal-footer"> | ||||
|                         <button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm"> | ||||
|  | @ -495,15 +462,18 @@ | |||
| import { Modal } from "bootstrap" | ||||
| import { ucfirst } from "../util.ts" | ||||
| import axios from "axios"; | ||||
| import { useToast } from "vue-toastification" | ||||
| 
 | ||||
| import Confirm from "./Confirm.vue"; | ||||
| import HiddenInput from "./HiddenInput.vue"; | ||||
| const toast = useToast() | ||||
| import Telegram from "./notifications/Telegram.vue"; | ||||
| import { useToast } from "vue-toastification" | ||||
| const toast = useToast(); | ||||
| 
 | ||||
| export default { | ||||
|     components: { | ||||
|         Confirm, | ||||
|         HiddenInput, | ||||
|         Telegram, | ||||
|     }, | ||||
|     props: {}, | ||||
|     data() { | ||||
|  | @ -519,17 +489,7 @@ export default { | |||
|             appriseInstalled: false, | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         telegramGetUpdatesURL() { | ||||
|             let token = "<YOUR BOT TOKEN HERE>" | ||||
| 
 | ||||
|             if (this.notification.telegramBotToken) { | ||||
|                 token = this.notification.telegramBotToken; | ||||
|             } | ||||
| 
 | ||||
|             return `https://api.telegram.org/bot${token}/getUpdates`; | ||||
|         }, | ||||
|     }, | ||||
|     watch: { | ||||
|         "notification.type"(to, from) { | ||||
|             let oldName; | ||||
|  | @ -615,32 +575,6 @@ export default { | |||
|                 } | ||||
|             }) | ||||
|         }, | ||||
| 
 | ||||
|         async autoGetTelegramChatID() { | ||||
|             try { | ||||
|                 let res = await axios.get(this.telegramGetUpdatesURL) | ||||
| 
 | ||||
|                 if (res.data.result.length >= 1) { | ||||
|                     let update = res.data.result[res.data.result.length - 1] | ||||
| 
 | ||||
|                     if (update.channel_post) { | ||||
|                         this.notification.telegramChatID = update.channel_post.chat.id; | ||||
|                     } else if (update.message) { | ||||
|                         this.notification.telegramChatID = update.message.chat.id; | ||||
|                     } else { | ||||
|                         throw new Error("Chat ID is not found, please send a message to this bot first") | ||||
|                     } | ||||
| 
 | ||||
|                 } else { | ||||
|                     throw new Error("Chat ID is not found, please send a message to this bot first") | ||||
|                 } | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 toast.error(error.message) | ||||
|             } | ||||
| 
 | ||||
|         }, | ||||
| 
 | ||||
|     }, | ||||
| } | ||||
| </script> | ||||
|  |  | |||
							
								
								
									
										98
									
								
								src/components/notifications/Telegram.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/components/notifications/Telegram.vue
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | |||
| <template> | ||||
|     <template v-if="$parent.notification.type === name"> | ||||
|         <div class="mb-3"> | ||||
|             <label for="telegram-bot-token" class="form-label">Bot Token</label> | ||||
|             <HiddenInput id="telegram-bot-token" v-model="$parent.notification.telegramBotToken" :required="true" autocomplete="one-time-code"></HiddenInput> | ||||
|             <div class="form-text"> | ||||
|                 You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>. | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="mb-3"> | ||||
|             <label for="telegram-chat-id" class="form-label">Chat ID</label> | ||||
| 
 | ||||
|             <div class="input-group mb-3"> | ||||
|                 <input id="telegram-chat-id" v-model="$parent.notification.telegramChatID" type="text" class="form-control" required> | ||||
|                 <button v-if="$parent.notification.telegramBotToken" class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID"> | ||||
|                     {{ $t("Auto Get") }} | ||||
|                 </button> | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="form-text"> | ||||
|                 Support Direct Chat / Group / Channel's Chat ID | ||||
| 
 | ||||
|                 <p style="margin-top: 8px;"> | ||||
|                     You can get your chat id by sending message to the bot and go to this url to view the chat_id: | ||||
|                 </p> | ||||
| 
 | ||||
|                 <p style="margin-top: 8px;"> | ||||
|                     <template v-if="$parent.notification.telegramBotToken"> | ||||
|                         <a :href="telegramGetUpdatesURL" target="_blank" style="word-break: break-word;">{{ telegramGetUpdatesURL }}</a> | ||||
|                     </template> | ||||
| 
 | ||||
|                     <template v-else> | ||||
|                         {{ telegramGetUpdatesURL }} | ||||
|                     </template> | ||||
|                 </p> | ||||
|             </div> | ||||
|         </div> | ||||
|     </template> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import HiddenInput from "../HiddenInput.vue"; | ||||
| import axios from "axios"; | ||||
| import { useToast } from "vue-toastification" | ||||
| const toast = useToast(); | ||||
| 
 | ||||
| export default { | ||||
|     components: { | ||||
|         HiddenInput, | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             name: "telegram", | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         telegramGetUpdatesURL() { | ||||
|             let token = "<YOUR BOT TOKEN HERE>" | ||||
| 
 | ||||
|             if (this.$parent.notification.telegramBotToken) { | ||||
|                 token = this.$parent.notification.telegramBotToken; | ||||
|             } | ||||
| 
 | ||||
|             return `https://api.telegram.org/bot${token}/getUpdates`; | ||||
|         }, | ||||
|     }, | ||||
|     mounted() { | ||||
| 
 | ||||
|     }, | ||||
|     methods: { | ||||
|         async autoGetTelegramChatID() { | ||||
|             try { | ||||
|                 let res = await axios.get(this.telegramGetUpdatesURL) | ||||
| 
 | ||||
|                 if (res.data.result.length >= 1) { | ||||
|                     let update = res.data.result[res.data.result.length - 1] | ||||
| 
 | ||||
|                     if (update.channel_post) { | ||||
|                         this.notification.telegramChatID = update.channel_post.chat.id; | ||||
|                     } else if (update.message) { | ||||
|                         this.notification.telegramChatID = update.message.chat.id; | ||||
|                     } else { | ||||
|                         throw new Error("Chat ID is not found, please send a message to this bot first") | ||||
|                     } | ||||
| 
 | ||||
|                 } else { | ||||
|                     throw new Error("Chat ID is not found, please send a message to this bot first") | ||||
|                 } | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 toast.error(error.message) | ||||
|             } | ||||
| 
 | ||||
|         }, | ||||
|     } | ||||
| } | ||||
| </script> | ||||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -119,4 +119,5 @@ export default { | |||
|     respTime: "Antw. Zeit (ms)", | ||||
|     notAvailableShort: "N/A", | ||||
|     Create: "Erstellen", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -118,5 +118,6 @@ export default { | |||
|     Create: "Create", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -109,5 +109,12 @@ export default { | |||
|     "Repeat Password": "Powtórz hasło", | ||||
|     respTime: "Czas odp. (ms)", | ||||
|     notAvailableShort: "N/A", | ||||
|     Create: "Stwórz" | ||||
|     Create: "Stwórz", | ||||
|     clearEventsMsg: "Are you sure want to delete all events for this monitor?", | ||||
|     clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?", | ||||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", | ||||
|     "Clear Data": "Clear Data", | ||||
|     Events: "Events", | ||||
|     Heartbeats: "Heartbeats" | ||||
|     Heartbeats: "Heartbeats", | ||||
|     "Auto Get": "Auto Get" | ||||
| } | ||||
|  |  | |||
|  | @ -115,5 +115,6 @@ export default { | |||
|     confirmClearStatisticsMsg: "是否確定刪除所有監測器的脈搏資料?(您的監測器會繼續正常運作)", | ||||
|     "Clear Data": "清除資料", | ||||
|     Events: "事件", | ||||
|     Heartbeats: "脈搏" | ||||
|     Heartbeats: "脈搏", | ||||
|     "Auto Get": "自動獲取" | ||||
| } | ||||
|  |  | |||
|  | @ -85,7 +85,12 @@ export default { | |||
|                 this.$root.toastRes(res) | ||||
| 
 | ||||
|                 if (res.ok) { | ||||
|                     this.$router.push("/") | ||||
|                     this.processing = true; | ||||
| 
 | ||||
|                     this.$root.login(this.username, this.password, (res) => { | ||||
|                         this.processing = false; | ||||
|                         this.$router.push("/") | ||||
|                     }) | ||||
|                 } | ||||
|             }) | ||||
|         }, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue