diff --git a/server/notification-providers/vk.js b/server/notification-providers/vk.js new file mode 100644 index 000000000..9912fa9a9 --- /dev/null +++ b/server/notification-providers/vk.js @@ -0,0 +1,44 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +class VK extends NotificationProvider { + name = "VK"; + + /** + * @inheritdoc + */ + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; + const url = "https://api.vk.ru/method/messages.send"; + + try { + const data = new URLSearchParams({ + access_token: notification.vkAccessToken, + v: notification.vkApiVersion, + peer_id: notification.vkPeerId, + message: msg, + dont_parse_links: notification.vkDontParseLinks ? "1" : "0", + random_id: String(Math.floor(Math.random() * 2147483647)), + }); + + const config = this.getAxiosConfigWithProxy({}); + const response = await axios.post(url, data, config); + + if (response.data?.error) { + throw new Error( + `VK API returned error ${response.data.error.error_code}: ${response.data.error.error_msg}` + ); + } + + if (typeof response.data?.response === "undefined") { + throw new Error("Invalid VK API response"); + } + + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = VK; diff --git a/server/notification.js b/server/notification.js index 6aeba5835..f790db432 100644 --- a/server/notification.js +++ b/server/notification.js @@ -91,6 +91,7 @@ const Whatsapp360messenger = require("./notification-providers/360messenger"); const Webpush = require("./notification-providers/Webpush"); const HaloPSA = require("./notification-providers/HaloPSA"); const Max = require("./notification-providers/max"); +const VK = require("./notification-providers/vk"); class Notification { providerList = {}; @@ -197,6 +198,7 @@ class Notification { new Webpush(), new HaloPSA(), new Max(), + new VK(), ]; for (let item of list) { if (!item.name) { diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 57bfd5f31..e9370b37e 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -334,6 +334,7 @@ export default { WPush: "WPush(wpush.cn)", YZJ: "YZJ (云之家自定义机器人)", SMSPlanet: "SMSPlanet.pl", + VK: "VK", }; // Sort by notification name alphabetically diff --git a/src/components/notifications/VK.vue b/src/components/notifications/VK.vue new file mode 100644 index 000000000..507d7465e --- /dev/null +++ b/src/components/notifications/VK.vue @@ -0,0 +1,57 @@ + + + diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 433258227..abb5a7636 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -88,6 +88,7 @@ import Webpush from "./Webpush.vue"; import HaloPSA from "./HaloPSA.vue"; import Resend from "./Resend.vue"; import Max from "./Max.vue"; +import VK from "./VK.vue"; /** * Manage all notification form. @@ -184,6 +185,7 @@ const NotificationFormList = { Webpush: Webpush, HaloPSA: HaloPSA, max: Max, + VK: VK, }; export default NotificationFormList; diff --git a/src/lang/en.json b/src/lang/en.json index 6235dbf30..378472d5f 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -660,6 +660,7 @@ "Number": "Number", "Recipients": "Recipients", "Access Token": "Access Token", + "API Version": "API Version", "Channel access token": "Channel access token", "Channel access token (Long-lived)": "Channel access token (Long-lived)", "Line Developers Console": "Line Developers Console", @@ -718,6 +719,11 @@ "noMonitorsOrStatusPagesSelectedError": "Cannot create maintenance without affected monitors or status pages", "passwordNotMatchMsg": "The repeat password does not match.", "notificationDescription": "Notifications must be assigned to a monitor to function.", + "Peer ID": "Peer ID", + "vkApiVersionDescription": "VK API version used for requests. Leave the default unless you specifically need another VK API version for compatibility.", + "vkDontParseLinks": "Disable link snippets", + "vkDontParseLinksDescription": "If enabled, VK will not generate link previews/snippets.", + "vkPeerIdDescription": "Enter the target VK peer_id. This value is sent to the API as-is.", "keywordDescription": "Search keyword in plain HTML or JSON response. The search is case-sensitive.", "invertKeywordDescription": "Look for the keyword to be absent rather than present.", "jsonQueryDescription": "Parse and extract specific data from the server's JSON response using JSON query or use \"$\" for the raw response, if not expecting JSON. The result is then compared to the expected value, as strings. See {0} for documentation and use {1} to experiment with queries.",