diff --git a/client/public/assets/locales/en.json b/client/public/assets/locales/en.json index 66adf751..90727920 100644 --- a/client/public/assets/locales/en.json +++ b/client/public/assets/locales/en.json @@ -311,6 +311,19 @@ "finished_message_placeholder": "%ping% ms, %download% Mbps, %upload% Mbps" } }, + "pushover": { + "title": "Pushover", + "fields": { + "token": "App token", + "user_key": "User key", + "error_message": "Error message", + "error_message_placeholder": "Error: %error%", + "send_failed": "Send error messages", + "send_finished": "Send finished messages", + "finished_message": "Finished message", + "finished_message_placeholder": "%ping% ms, %download% Mbps, %upload% Mbps" + } + }, "healthChecks": { "title": "HealthChecks", "fields": { diff --git a/client/src/App.jsx b/client/src/App.jsx index d11b489b..83a86fd4 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -20,8 +20,10 @@ import {NodeProvider} from "@/common/contexts/Node"; import { library } from '@fortawesome/fontawesome-svg-core'; import { fas } from '@fortawesome/free-solid-svg-icons'; import { fab } from "@fortawesome/free-brands-svg-icons"; +import {PushOverIcon} from "@/common/assets/icons/pushover"; library.add(fas, fab); +library.add(PushOverIcon); const MainContent = () => { const [view] = useContext(ViewContext); diff --git a/client/src/common/assets/icons/pushover.js b/client/src/common/assets/icons/pushover.js new file mode 100644 index 00000000..536d7a13 --- /dev/null +++ b/client/src/common/assets/icons/pushover.js @@ -0,0 +1,8 @@ +export const PushOverIcon = { + icon: [ + 600, 600, [], "", + "M 280.949 172.514 L 355.429 162.714 L 282.909 326.374 L 282.909 326.374 C 295.649 325.394 308.142 321.067 320.389 313.394 L 320.389 313.394 L 320.389 313.394 C 332.642 305.714 343.916 296.077 354.209 284.484 L 354.209 284.484 L 354.209 284.484 C 364.496 272.884 373.396 259.981 380.909 245.774 L 380.909 245.774 L 380.909 245.774 C 388.422 231.561 393.812 217.594 397.079 203.874 L 397.079 203.874 L 397.079 203.874 C 399.039 195.381 399.939 187.214 399.779 179.374 L 399.779 179.374 L 399.779 179.374 C 399.612 171.534 397.569 164.674 393.649 158.794 L 393.649 158.794 L 393.649 158.794 C 389.729 152.914 383.766 148.177 375.759 144.584 L 375.759 144.584 L 375.759 144.584 C 367.759 140.991 356.899 139.194 343.179 139.194 L 343.179 139.194 L 343.179 139.194 C 327.172 139.194 311.409 141.807 295.889 147.034 L 295.889 147.034 L 295.889 147.034 C 280.376 152.261 266.002 159.857 252.769 169.824 L 252.769 169.824 L 252.769 169.824 C 239.542 179.784 228.029 192.197 218.229 207.064 L 218.229 207.064 L 218.229 207.064 C 208.429 221.924 201.406 238.827 197.159 257.774 L 197.159 257.774 L 197.159 257.774 C 195.526 263.981 194.546 268.961 194.219 272.714 L 194.219 272.714 L 194.219 272.714 C 193.892 276.474 193.812 279.577 193.979 282.024 L 193.979 282.024 L 193.979 282.024 C 194.139 284.477 194.462 286.357 194.949 287.664 L 194.949 287.664 L 194.949 287.664 C 195.442 288.971 195.852 290.277 196.179 291.584 L 196.179 291.584 L 196.179 291.584 C 179.519 291.584 167.349 288.234 159.669 281.534 L 159.669 281.534 L 159.669 281.534 C 151.996 274.841 150.119 263.164 154.039 246.504 L 154.039 246.504 L 154.039 246.504 C 157.959 229.191 166.862 212.694 180.749 197.014 L 180.749 197.014 L 180.749 197.014 C 194.629 181.334 211.122 167.531 230.229 155.604 L 230.229 155.604 L 230.229 155.604 C 249.342 143.684 270.249 134.214 292.949 127.194 L 292.949 127.194 L 292.949 127.194 C 315.656 120.167 337.789 116.654 359.349 116.654 L 359.349 116.654 L 359.349 116.654 C 378.296 116.654 394.219 119.347 407.119 124.734 L 407.119 124.734 L 407.119 124.734 C 420.026 130.127 430.072 137.234 437.259 146.054 L 437.259 146.054 L 437.259 146.054 C 444.446 154.874 448.936 165.164 450.729 176.924 L 450.729 176.924 L 450.729 176.924 C 452.529 188.684 451.959 200.934 449.019 213.674 L 449.019 213.674 L 449.019 213.674 C 445.426 229.027 438.646 244.464 428.679 259.984 L 428.679 259.984 L 428.679 259.984 C 418.719 275.497 406.226 289.544 391.199 302.124 L 391.199 302.124 L 391.199 302.124 C 376.172 314.697 358.939 324.904 339.499 332.744 L 339.499 332.744 L 339.499 332.744 C 320.066 340.584 299.406 344.504 277.519 344.504 L 277.519 344.504 L 275.069 344.504 L 212.839 484.154 L 142.279 484.154 L 280.949 172.514 Z" + ], + iconName: "pushover", + prefix: "fas" +} \ No newline at end of file diff --git a/client/src/common/languages/bg.webp b/client/src/common/assets/languages/bg.webp similarity index 100% rename from client/src/common/languages/bg.webp rename to client/src/common/assets/languages/bg.webp diff --git a/client/src/common/languages/br.webp b/client/src/common/assets/languages/br.webp similarity index 100% rename from client/src/common/languages/br.webp rename to client/src/common/assets/languages/br.webp diff --git a/client/src/common/languages/de.webp b/client/src/common/assets/languages/de.webp similarity index 100% rename from client/src/common/languages/de.webp rename to client/src/common/assets/languages/de.webp diff --git a/client/src/common/languages/en.webp b/client/src/common/assets/languages/en.webp similarity index 100% rename from client/src/common/languages/en.webp rename to client/src/common/assets/languages/en.webp diff --git a/client/src/common/languages/es.webp b/client/src/common/assets/languages/es.webp similarity index 100% rename from client/src/common/languages/es.webp rename to client/src/common/assets/languages/es.webp diff --git a/client/src/common/languages/fr.webp b/client/src/common/assets/languages/fr.webp similarity index 100% rename from client/src/common/languages/fr.webp rename to client/src/common/assets/languages/fr.webp diff --git a/client/src/common/languages/it.webp b/client/src/common/assets/languages/it.webp similarity index 100% rename from client/src/common/languages/it.webp rename to client/src/common/assets/languages/it.webp diff --git a/client/src/common/languages/nl.webp b/client/src/common/assets/languages/nl.webp similarity index 100% rename from client/src/common/languages/nl.webp rename to client/src/common/assets/languages/nl.webp diff --git a/client/src/common/languages/ru.webp b/client/src/common/assets/languages/ru.webp similarity index 100% rename from client/src/common/languages/ru.webp rename to client/src/common/assets/languages/ru.webp diff --git a/client/src/common/languages/tr.webp b/client/src/common/assets/languages/tr.webp similarity index 100% rename from client/src/common/languages/tr.webp rename to client/src/common/assets/languages/tr.webp diff --git a/client/src/common/languages/zh.webp b/client/src/common/assets/languages/zh.webp similarity index 100% rename from client/src/common/languages/zh.webp rename to client/src/common/assets/languages/zh.webp diff --git a/client/src/i18n.js b/client/src/i18n.js index 0429a9ad..44ac8104 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -2,17 +2,17 @@ import i18n from "i18next"; import {initReactI18next} from "react-i18next"; import LanguageDetector from 'i18next-browser-languagedetector'; import HttpApi from 'i18next-http-backend'; -import EnglishFlag from "@/common/languages/en.webp"; -import GermanFlag from "@/common/languages/de.webp"; -import BulgarianFlag from "@/common/languages/bg.webp"; -import ChineseFlag from "@/common/languages/zh.webp"; -import DutchFlag from "@/common/languages/nl.webp"; -import FranceFlag from "@/common/languages/fr.webp"; -import ItalianFlag from "@/common/languages/it.webp"; -import PortugueseBrazilFlag from "@/common/languages/br.webp"; -import RussianFlag from "@/common/languages/ru.webp"; -import SpanishFlag from "@/common/languages/es.webp"; -import TurkishFlag from "@/common/languages/tr.webp"; +import EnglishFlag from "@/common/assets/languages/en.webp"; +import GermanFlag from "@/common/assets/languages/de.webp"; +import BulgarianFlag from "@/common/assets/languages/bg.webp"; +import ChineseFlag from "@/common/assets/languages/zh.webp"; +import DutchFlag from "@/common/assets/languages/nl.webp"; +import FranceFlag from "@/common/assets/languages/fr.webp"; +import ItalianFlag from "@/common/assets/languages/it.webp"; +import PortugueseBrazilFlag from "@/common/assets/languages/br.webp"; +import RussianFlag from "@/common/assets/languages/ru.webp"; +import SpanishFlag from "@/common/assets/languages/es.webp"; +import TurkishFlag from "@/common/assets/languages/tr.webp"; if (localStorage.getItem('language') === null) localStorage.setItem('language', navigator.language.split('-')[0]); diff --git a/server/integrations/pushover.js b/server/integrations/pushover.js new file mode 100644 index 00000000..999c2581 --- /dev/null +++ b/server/integrations/pushover.js @@ -0,0 +1,47 @@ +const axios = require("axios"); +const {replaceVariables} = require("../util/helpers"); + +const BASE_URL = "https://api.pushover.net/1"; + +const defaults = { + finished: "A speedtest is finished:\nPing: %ping% ms\nUpload: %upload% Mbps\nDownload: %download% Mbps", + failed: "A speedtest has failed. Reason: %error%" +} + +module.exports = (registerEvent) => { + registerEvent('testFinished', async (integration, data, triggerActivity) => { + if (!integration.data.send_finished) return; + + const message = replaceVariables(integration.data.finished_message || defaults.finished, data); + + axios.post(`${BASE_URL}/messages.json`, { + token: integration.data.token, + user: integration.data.user_key, message + }).then(() => triggerActivity()) + .catch(() => triggerActivity(true)); + }); + + registerEvent('testFailed', async (integration, error, triggerActivity) => { + if (!integration.data.send_failed) return; + + const message = replaceVariables(integration.data.error_message || defaults.failed, {error}); + + axios.post(`${BASE_URL}/messages.json`, { + token: integration.data.token, + user: integration.data.user_key, message + }).then(() => triggerActivity()) + .catch(() => triggerActivity(true)); + }); + + return { + icon: "fa-solid fa-pushover", + fields: [ + {name: "token", type: "text", required: true, regex: /^[a-z0-9]{30}$/}, + {name: "user_key", type: "text", required: true, regex: /^[a-z0-9]{30}$/}, + {name: "send_finished", type: "boolean", required: false}, + {name: "finished_message", type: "textarea", required: false}, + {name: "send_failed", type: "boolean", required: false}, + {name: "error_message", type: "textarea", required: false} + ] + }; +} \ No newline at end of file