mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-05-20 06:02:33 +02:00
Merge 43c3fda914
into 289e824a5d
This commit is contained in:
commit
419b94d207
11 changed files with 220 additions and 18035 deletions
|
@ -3,6 +3,7 @@ import { defineConfig } from "vite";
|
|||
import visualizer from "rollup-plugin-visualizer";
|
||||
import viteCompression from "vite-plugin-compression";
|
||||
import VueDevTools from "vite-plugin-vue-devtools";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
|
||||
const postCssScss = require("postcss-scss");
|
||||
const postcssRTLCSS = require("postcss-rtlcss");
|
||||
|
@ -32,6 +33,12 @@ export default defineConfig({
|
|||
filter: viteCompressionFilter,
|
||||
}),
|
||||
VueDevTools(),
|
||||
VitePWA({
|
||||
registerType: null,
|
||||
srcDir: "src",
|
||||
filename: "serviceWorker.ts",
|
||||
strategies: "injectManifest",
|
||||
}),
|
||||
],
|
||||
css: {
|
||||
postcss: {
|
||||
|
|
18035
package-lock.json
generated
18035
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -141,6 +141,7 @@
|
|||
"tcp-ping": "~0.1.1",
|
||||
"thirty-two": "~1.0.2",
|
||||
"tough-cookie": "~4.1.3",
|
||||
"web-push": "^3.6.7",
|
||||
"ws": "^8.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -155,6 +156,7 @@
|
|||
"@testcontainers/rabbitmq": "^10.13.2",
|
||||
"@types/bootstrap": "~5.1.9",
|
||||
"@types/node": "^20.8.6",
|
||||
"@types/web-push": "^3.6.4",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||
"@typescript-eslint/parser": "^6.7.5",
|
||||
"@vitejs/plugin-vue": "~5.0.1",
|
||||
|
@ -193,6 +195,7 @@
|
|||
"v-pagination-3": "~0.1.7",
|
||||
"vite": "~5.4.15",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-pwa": "^0.21.1",
|
||||
"vite-plugin-vue-devtools": "^7.0.15",
|
||||
"vue": "~3.4.2",
|
||||
"vue-chartjs": "~5.2.0",
|
||||
|
|
51
server/notification-providers/Webpush.js
Normal file
51
server/notification-providers/Webpush.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const { UP } = require("../../src/util");
|
||||
const webpush = require("web-push");
|
||||
const { setting } = require("../util-server");
|
||||
|
||||
class Webpush extends NotificationProvider {
|
||||
name = "Webpush";
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
const okMsg = "Sent Successfully.";
|
||||
|
||||
try {
|
||||
const publicVapidKey = await setting("webpushPublicVapidKey");
|
||||
const privateVapidKey = await setting("webpushPrivateVapidKey");
|
||||
|
||||
webpush.setVapidDetails("https://github.com/louislam/uptime-kuma", publicVapidKey, privateVapidKey);
|
||||
|
||||
if (heartbeatJSON === null && monitorJSON === null) {
|
||||
// Test message
|
||||
const data = JSON.stringify({
|
||||
title: "TEST",
|
||||
body: "Test Alert - " + msg
|
||||
});
|
||||
|
||||
await webpush.sendNotification(notification.subscription, data);
|
||||
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
const title = `Monitor ${heartbeatJSON["status"] === UP ? "UP" : "DOWN"}`;
|
||||
const down = "❌ " + monitorJSON["name"] + " is DOWN ❌";
|
||||
const up = "✅ " + monitorJSON["name"] + " is UP ✅";
|
||||
|
||||
const data = JSON.stringify({
|
||||
title: title,
|
||||
body: `${heartbeatJSON["status"] === UP ? up : down}`
|
||||
});
|
||||
|
||||
await webpush.sendNotification(notification.subscription, data);
|
||||
|
||||
return okMsg;
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Webpush;
|
|
@ -74,6 +74,7 @@ const Cellsynt = require("./notification-providers/cellsynt");
|
|||
const Onesender = require("./notification-providers/onesender");
|
||||
const Wpush = require("./notification-providers/wpush");
|
||||
const SendGrid = require("./notification-providers/send-grid");
|
||||
const Webpush = require("./notification-providers/Webpush");
|
||||
const YZJ = require("./notification-providers/yzj");
|
||||
const SMSPlanet = require("./notification-providers/sms-planet");
|
||||
const SpugPush = require("./notification-providers/spugpush");
|
||||
|
@ -167,6 +168,7 @@ class Notification {
|
|||
new Cellsynt(),
|
||||
new Wpush(),
|
||||
new SendGrid(),
|
||||
new Webpush(),
|
||||
new YZJ(),
|
||||
new SMSPlanet(),
|
||||
new SpugPush(),
|
||||
|
|
|
@ -96,6 +96,8 @@ const { getSettings, setSettings, setting, initJWTSecret, checkLogin, doubleChec
|
|||
log.debug("server", "Importing Notification");
|
||||
const { Notification } = require("./notification");
|
||||
Notification.init();
|
||||
log.debug("server", "Importing Web-Push");
|
||||
const webpush = require("web-push");
|
||||
|
||||
log.debug("server", "Importing Database");
|
||||
const Database = require("./database");
|
||||
|
@ -1488,6 +1490,32 @@ let needSetup = false;
|
|||
}
|
||||
});
|
||||
|
||||
socket.on("getWebpushVapidPublicKey", async (callback) => {
|
||||
try {
|
||||
let publicVapidKey = await Settings.get("webpushPublicVapidKey");
|
||||
|
||||
if (!publicVapidKey) {
|
||||
log.debug("webpush", "Generating new VAPID keys");
|
||||
const vapidKeys = webpush.generateVAPIDKeys();
|
||||
|
||||
await Settings.set("webpushPrivateVapidKey", vapidKeys.privateKey);
|
||||
await Settings.set("webpushPublicVapidKey", vapidKeys.publicKey);
|
||||
|
||||
publicVapidKey = vapidKeys.publicKey;
|
||||
}
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: publicVapidKey,
|
||||
});
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("clearEvents", async (monitorID, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
|
|
@ -169,6 +169,7 @@ export default {
|
|||
"gtxmessaging": "GtxMessaging",
|
||||
"Cellsynt": "Cellsynt",
|
||||
"SendGrid": "SendGrid",
|
||||
"Webpush": "Webpush",
|
||||
"notifery": "Notifery"
|
||||
};
|
||||
|
||||
|
|
98
src/components/notifications/Webpush.vue
Normal file
98
src/components/notifications/Webpush.vue
Normal file
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<button
|
||||
class="mb-3"
|
||||
type="button"
|
||||
:class="[
|
||||
'btn',
|
||||
browserSupportsServiceWorkers ? 'btn-primary' : 'btn-danger'
|
||||
]"
|
||||
:disabled="!btnEnabled"
|
||||
@click="registerWebpush"
|
||||
>
|
||||
<div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
|
||||
<span v-else-if="$parent.notification.subscription" class="me-1">✓</span>
|
||||
{{ btnText }}
|
||||
</button>
|
||||
|
||||
<div class="form-text">
|
||||
{{ $t("Webpush Helptext") }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
btnEnabled: false,
|
||||
btnText: "",
|
||||
processing: false,
|
||||
browserSupportsServiceWorkers: false,
|
||||
publicVapidKey: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.$parent.notification.subscription) {
|
||||
this.btnEnabled = false;
|
||||
this.browserSupportsServiceWorkers = true;
|
||||
this.btnText = this.$t("Notifications Enabled");
|
||||
} else {
|
||||
if (("serviceWorker" in navigator)) {
|
||||
this.btnText = this.$t("Allow Notifications");
|
||||
this.browserSupportsServiceWorkers = true;
|
||||
this.btnEnabled = true;
|
||||
} else {
|
||||
this.btnText = this.$t("Browser not supported");
|
||||
this.browserSupportsServiceWorkers = false;
|
||||
this.btnEnabled = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async registerWebpush() {
|
||||
this.processing = true;
|
||||
|
||||
try {
|
||||
const publicKey = await new Promise((resolve, reject) => {
|
||||
this.$root.getSocket().emit("getWebpushVapidPublicKey", (resp) => {
|
||||
if (!resp.ok) {
|
||||
reject(new Error(resp.msg));
|
||||
}
|
||||
console.log(resp.msg);
|
||||
resolve(resp.msg);
|
||||
});
|
||||
});
|
||||
|
||||
const permission = await Notification.requestPermission();
|
||||
if (permission !== "granted") {
|
||||
this.$root.toastRes({
|
||||
ok: false,
|
||||
msg: this.$t("Unable to get permission to notify"),
|
||||
});
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
|
||||
const subscription = await registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: publicKey,
|
||||
});
|
||||
|
||||
this.$parent.notification.subscription = subscription;
|
||||
this.btnEnabled = false;
|
||||
this.browserSupportsServiceWorkers = true;
|
||||
this.btnText = this.$t("Notifications Enabled");
|
||||
} catch (error) {
|
||||
console.error("Subscription failed:", error);
|
||||
this.$root.toastRes({
|
||||
ok: false,
|
||||
msg: error
|
||||
});
|
||||
} finally {
|
||||
this.processing = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -73,6 +73,7 @@ import Cellsynt from "./Cellsynt.vue";
|
|||
import WPush from "./WPush.vue";
|
||||
import SIGNL4 from "./SIGNL4.vue";
|
||||
import SendGrid from "./SendGrid.vue";
|
||||
import Webpush from "./Webpush.vue";
|
||||
import YZJ from "./YZJ.vue";
|
||||
import SMSPlanet from "./SMSPlanet.vue";
|
||||
|
||||
|
@ -156,6 +157,7 @@ const NotificationFormList = {
|
|||
"Cellsynt": Cellsynt,
|
||||
"WPush": WPush,
|
||||
"SendGrid": SendGrid,
|
||||
"Webpush": Webpush,
|
||||
"YZJ": YZJ,
|
||||
"SMSPlanet": SMSPlanet,
|
||||
};
|
||||
|
|
|
@ -1074,6 +1074,11 @@
|
|||
"rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.",
|
||||
"SendGrid API Key": "SendGrid API Key",
|
||||
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas",
|
||||
"Notifications Enabled": "Notifications Enabled",
|
||||
"Allow Notifications": "Allow Notifications",
|
||||
"Browser not supported": "Browser not supported",
|
||||
"Unable to get permission to notify": "Unable to get permission to notify (request either denied or ignored).",
|
||||
"Webpush Helptext": "Web push only works with SSL (HTTPS) connections. For iOS devices, webpage must be added to homescreen beforehand.",
|
||||
"Custom URL": "Custom URL",
|
||||
"customUrlDescription": "Will be used as the clickable URL instead of the monitor's one.",
|
||||
"OneChatAccessToken": "OneChat Access Token",
|
||||
|
|
23
src/serviceWorker.ts
Normal file
23
src/serviceWorker.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Needed per Vite PWA docs
|
||||
import { precacheAndRoute } from 'workbox-precaching'
|
||||
declare let self: ServiceWorkerGlobalScope
|
||||
precacheAndRoute(self.__WB_MANIFEST)
|
||||
|
||||
// Receive push notifications
|
||||
self.addEventListener('push', function (event) {
|
||||
if (self.Notification?.permission !== 'granted') {
|
||||
console.error("Notifications aren't supported or permission not granted!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data) {
|
||||
let message = event.data.json();
|
||||
try {
|
||||
self.registration.showNotification(message.title, {
|
||||
body: message.body,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to show notification:', error);
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Add table
Reference in a new issue