diff --git a/README.md b/README.md index cfa4554..0e39617 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ See instructions to run Wallos below. - openssl - sqlite3 - zip + - mbstring + - fpm #### Docker diff --git a/endpoints/cronjobs/sendnotifications.php b/endpoints/cronjobs/sendnotifications.php index d69338c..07934f1 100644 --- a/endpoints/cronjobs/sendnotifications.php +++ b/endpoints/cronjobs/sendnotifications.php @@ -61,6 +61,8 @@ while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) { $telegramNotificationsEnabled = false; $webhookNotificationsEnabled = false; $pushoverNotificationsEnabled = false; + $pushplusNotificationsEnabled = false; + $mattermostNotificationsEnabled = false; $discordNotificationsEnabled = false; $ntfyNotificationsEnabled = false; @@ -74,7 +76,6 @@ while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) { $days = $row['days']; } - // Check if email notifications are enabled and get the settings $query = "SELECT * FROM email_notifications WHERE user_id = :userId"; $stmt = $db->prepare($query); @@ -141,6 +142,19 @@ while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) { $pushplusNotificationsEnabled = $row['enabled']; $pushplus['token'] = $row["token"]; } + // Check if Mattermost notifications are enabled and get the settings + $query = "SELECT * FROM mattermost_notifications WHERE user_id = :userID"; + $stmt = $db->prepare($query); + $stmt->bindValue(':userID', $userId, SQLITE3_INTEGER); + $result = $stmt->execute(); + + if ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $mattermostNotificationsEnabled = $row['enabled']; + $mattermost['webhook_url'] = $row['webhook_url']; + $mattermost['bot_username'] = $row['bot_username']; + $mattermost['bot_icon_emoji'] = $row['bot_icon_emoji']; + } + // Check if Pushover notifications are enabled and get the settings $query = "SELECT * FROM pushover_notifications WHERE user_id = :userId"; $stmt = $db->prepare($query); @@ -184,7 +198,7 @@ while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) { $notificationsEnabled = $emailNotificationsEnabled || $gotifyNotificationsEnabled || $telegramNotificationsEnabled || $webhookNotificationsEnabled || $pushoverNotificationsEnabled || $discordNotificationsEnabled ||$pushplusNotificationsEnabled|| - $ntfyNotificationsEnabled; + $mattermostNotificationsEnabled || $ntfyNotificationsEnabled; // If no notifications are enabled, no need to run if (!$notificationsEnabled) { @@ -569,6 +583,69 @@ while ($userToNotify = $usersToNotify->fetchArray(SQLITE3_ASSOC)) { } } + // Mattermost notifications if enabled + if ($mattermostNotificationsEnabled) { + foreach ($notify as $userId => $perUser) { + // Get name of user from household table + $stmt = $db->prepare('SELECT * FROM household WHERE id = :userId'); + $stmt->bindValue(':userId', $userId, SQLITE3_INTEGER); + $result = $stmt->execute(); + $user = $result->fetchArray(SQLITE3_ASSOC); + + // Build Message Content + $messageContent = ""; + if ($user['name']) { + $messageContent = $user['name'] . ", the following subscriptions are up for renewal:\n"; + } else { + $messageContent = "The following subscriptions are up for renewal:\n"; + } + + foreach ($perUser as $subscription) { + $dayText = getDaysText($subscription['days']); + $messageContent .= $subscription['name'] . " for " . $subscription['formatted_price'] . " (" . $dayText . ")\n"; + } + + // Prepare Mattermost Data + $webhook_url = $mattermost['webhook_url']; + $data = array( + 'username' => $mattermost['bot_username'], + 'icon_emoji' => $mattermost['bot_icon_emoji'], + 'text' => mb_convert_encoding($messageContent, 'UTF-8', 'auto'), + ); + + $data_string = json_encode($data); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $webhook_url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt( + $ch, + CURLOPT_HTTPHEADER, + array( + 'Content-Type: application/json' + ), + ); + + $result = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if ($result === false) { + echo "Error sending Mattermost notifications: " . curl_error($ch) . "
"; + } else { + $resultData = json_decode($result, true); + if (isset($resultData['code']) && $resultData['code'] == 200) { + echo "Mattermost Notifications sent successfully
"; + } else { + $errorMsg = isset($resultData['msg']) ? $resultData['msg'] : 'Unknown error'; + echo "Mattermost API error: " . $errorMsg . "
"; + } + } + curl_close($ch); + } + } + // Pushover notifications if enabled if ($pushoverNotificationsEnabled) { foreach ($notify as $userId => $perUser) { diff --git a/endpoints/notifications/savemattermostnotifications.php b/endpoints/notifications/savemattermostnotifications.php new file mode 100755 index 0000000..2132b34 --- /dev/null +++ b/endpoints/notifications/savemattermostnotifications.php @@ -0,0 +1,72 @@ + false, + "message" => translate('session_expired', $i18n) + ])); +} + +if ($_SERVER["REQUEST_METHOD"] === "POST") { + $postData = file_get_contents("php://input"); + $data = json_decode($postData, true); + + if (!isset($data["webhook_url"]) || $data["webhook_url"] == "") { + $response = [ + "success" => false, + "message" => translate('fill_mandatory_fields', $i18n) + ]; + echo json_encode($response); + } else { + $enabled = $data["enabled"]; + $webhook_url = $data["webhook_url"]; + $bot_username = $data["bot_username"]; + $bot_iconemoji = $data["bot_icon_emoji"]; + + $query = "SELECT COUNT(*) FROM mattermost_notifications WHERE user_id = :userId"; + $stmt = $db->prepare($query); + $stmt->bindParam(":userId", $userId, SQLITE3_INTEGER); + $result = $stmt->execute(); + + if ($result === false) { + $response = [ + "success" => false, + "message" => translate('error_saving_notifications', $i18n) + ]; + echo json_encode($response); + } else { + $row = $result->fetchArray(); + $count = $row[0]; + if ($count == 0) { + $query = "INSERT INTO mattermost_notifications (enabled, webhook_url, user_id, bot_username, bot_icon_emoji) + VALUES (:enabled, :webhook_url, :userId, :bot_username, :bot_icon_emoji)"; + } else { + $query = "UPDATE mattermost_notifications + SET enabled = :enabled, webhook_url = :webhook_url WHERE user_id = :userId"; + } + + $stmt = $db->prepare($query); + $stmt->bindValue(':enabled', $enabled, SQLITE3_INTEGER); + $stmt->bindValue(':webhook_url', $webhook_url, SQLITE3_TEXT); + $stmt->bindValue(':userId', $userId, SQLITE3_INTEGER); + $stmt->bindValue(':bot_username', $bot_username, SQLITE3_TEXT); + $stmt->bindValue(':bot_icon_emoji', $bot_iconemoji, SQLITE3_TEXT); + + if ($stmt->execute()) { + $response = [ + "success" => true, + "message" => translate('notifications_settings_saved', $i18n) + ]; + echo json_encode($response); + } else { + $response = [ + "success" => false, + "message" => translate('error_saving_notifications', $i18n) + ]; + echo json_encode($response); + } + } + } +} +?> \ No newline at end of file diff --git a/endpoints/notifications/testmattermostnotifications.php b/endpoints/notifications/testmattermostnotifications.php new file mode 100755 index 0000000..c72a5da --- /dev/null +++ b/endpoints/notifications/testmattermostnotifications.php @@ -0,0 +1,97 @@ + false, + "message" => translate('session_expired', $i18n) + ])); +} + +if ($_SERVER["REQUEST_METHOD"] === "POST") { + $postData = file_get_contents("php://input"); + $data = json_decode($postData, true); + + if ( + !isset($data["webhook_url"]) || $data["webhook_url"] == "" || + !isset($data["bot_username"]) || $data["bot_username"] == "" || + !isset($data["bot_icon_emoji"]) || $data["bot_icon_emoji"] == "" + ) { + $response = [ + "success" => false, + "message" => translate('fill_mandatory_fields', $i18n) + ]; + echo json_encode($response); + } else { + // Set the message parameters + $title = translate('wallos_notification', $i18n); + $message = translate('test_notification', $i18n); + + $webhook_url = $data["webhook_url"]; + $bot_username = $data["bot_username"]; + $bot_icon_emoji = $data["bot_icon_emoji"]; + + // Validate URL scheme + $parsedUrl = parse_url($webhook_url); + if ( + !isset($parsedUrl['scheme']) || + !in_array(strtolower($parsedUrl['scheme']), ['http', 'https']) || + !filter_var($webhook_url, FILTER_VALIDATE_URL) + ) { + die(json_encode([ + "success" => false, + "message" => translate("error", $i18n) + ])); + } + + $postfields = [ + 'text' => $message, + ]; + + if (!empty($bot_username)) { + $postfields['username'] = $bot_username; + } + + if (!empty($bot_icon_emoji)) { + $postfields['icon_emoji'] = $bot_icon_emoji; + } + + $ch = curl_init(); + + // Set the URL and other options + curl_setopt($ch, CURLOPT_URL, $webhook_url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postfields)); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json' + ]); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + // Execute the request + $response = curl_exec($ch); + + // Close the cURL session + curl_close($ch); + + // Check if the message was sent successfully + if ($response === false) { + die(json_encode([ + "success" => false, + "message" => translate('notification_failed', $i18n) + ])); + } else { + die(json_encode([ + "success" => true, + "message" => translate('notification_sent_successfuly', $i18n) + ])); + } + } +} else { + die(json_encode([ + "success" => false, + "message" => translate("invalid_request_method", $i18n) + ])); +} + +?> \ No newline at end of file diff --git a/includes/i18n/en.php b/includes/i18n/en.php index b21b8e0..c3570b2 100644 --- a/includes/i18n/en.php +++ b/includes/i18n/en.php @@ -196,6 +196,10 @@ $i18n = [ "telegram_chat_id" => "Telegram Chat ID", "pushplus" => "Pushplus", "pushplus_token" => "Pushplus Token", + "mattermost" => "Mattermost", + "mattermost_webhook_url" => "WebHook URL", + "mattermost_bot_username" => "Bot Username", + "mattermost_bot_icon_emoji" => "Bot Icon Emoji", "webhook" => "Webhook", "webhook_url" => "Webhook URL", "request_method" => "Request Method", diff --git a/includes/i18n/pt.php b/includes/i18n/pt.php index fc6e473..145b1c9 100644 --- a/includes/i18n/pt.php +++ b/includes/i18n/pt.php @@ -195,6 +195,10 @@ $i18n = [ "telegram_chat_id" => "ID do Chat Telegram", "pushplus" => "Pushplus", "pushplus_token" => "Token do Pushplus", + "mattermost" => "Mattermost", + "mattermost_webhook_url" => "URL do Hook", + "mattermost_bot_username" => "Nome de Utilizador do Bot", + "mattermost_bot_icon_emoji" => "Icon Emoji do Bot", "webhook" => "Webhook", "webhook_url" => "URL do Webhook", "request_method" => "Método de Pedido", diff --git a/migrations/000041.php b/migrations/000041.php new file mode 100755 index 0000000..6c3bb65 --- /dev/null +++ b/migrations/000041.php @@ -0,0 +1,16 @@ +query("SELECT name FROM sqlite_master WHERE type='table' AND name='mattermost_notifications'"); +$tableExists = $tableQuery->fetchArray(SQLITE3_ASSOC); +if ($tableExists === false) { + $db->exec(" + CREATE TABLE mattermost_notifications ( + enabled INTEGER NOT NULL DEFAULT 0, + user_id INTEGER, + webhook_url TEXT DEFAULT '', + bot_username TEXT DEFAULT '', + bot_icon_emoji TEXT DEFAULT '' + ); + "); +} \ No newline at end of file diff --git a/scripts/notifications.js b/scripts/notifications.js index bd4b87f..123f802 100644 --- a/scripts/notifications.js +++ b/scripts/notifications.js @@ -216,6 +216,44 @@ function saveNotificationsPushPlusButton() { makeFetchCall('endpoints/notifications/savepushplusnotifications.php', data, button); } +function testNotificationsMattermostButton() { + const button = document.getElementById("testNotificationsMattermost"); + button.disabled = true; + + const enabled = document.getElementById("mattermostenabled").checked ? 1 : 0; + const webhook_url = document.getElementById("mattermostwebhookurl").value; + const bot_username = document.getElementById("mattermostbotusername").value; + const bot_icon_emoji = document.getElementById("mattermostboticonemoji").value; + + const data = { + enabled: enabled, + webhook_url: webhook_url, + bot_username: bot_username, + bot_icon_emoji: bot_icon_emoji + }; + + makeFetchCall('endpoints/notifications/testmattermostnotifications.php', data, button); +} + +function saveNotificationsMattermostButton() { + const button = document.getElementById("saveNotificationsMattermost"); + button.disabled = true; + + const enabled = document.getElementById("mattermostenabled").checked ? 1 : 0; + const webhook_url = document.getElementById("mattermostwebhookurl").value; + const bot_username = document.getElementById("mattermostbotusername").value; + const bot_icon_emoji = document.getElementById("mattermostboticonemoji").value; + + const data = { + enabled: enabled, + webhook_url: webhook_url, + bot_username: bot_username, + bot_icon_emoji: bot_icon_emoji + }; + + makeFetchCall('endpoints/notifications/savemattermostnotifications.php', data, button); +} + function saveNotificationsGotifyButton() { const button = document.getElementById("saveNotificationsGotify"); button.disabled = true; diff --git a/settings.php b/settings.php index 962e00b..78a0d47 100644 --- a/settings.php +++ b/settings.php @@ -240,6 +240,28 @@ $userData['currency_symbol'] = $currencies[$main_currency]['symbol']; $notificationsPushPlus['token'] = ""; } + // Mattermost notifications + $sql = "SELECT * FROM mattermost_notifications WHERE user_id = :userID LIMIT 1"; + $stmt = $db->prepare($sql); + $stmt->bindValue(':userID', $userId, SQLITE3_INTEGER); + $result = $stmt->execute(); + + $rowCount = 0; + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $notificationsMattermost['enabled'] = $row['enabled']; + $notificationsMattermost['webhook_url'] = $row['webhook_url']; + $notificationsMattermost['bot_username'] = $row['bot_username']; + $notificationsMattermost['bot_icon_emoji'] = $row['bot_icon_emoji']; + $rowCount++; + } + + if ($rowCount == 0) { + $notificationsMattermost['enabled'] = 0; + $notificationsMattermost['webhook_url'] = ""; + $notificationsMattermost['bot_username'] = ""; + $notificationsMattermost['bot_icon_emoji'] = ""; + } + // Ntfy notifications $sql = "SELECT * FROM ntfy_notifications WHERE user_id = :userId LIMIT 1"; $stmt = $db->prepare($sql); @@ -597,6 +619,44 @@ $userData['currency_symbol'] = $currencies[$main_currency]['symbol']; +
+
+

+ + +

+
+
+
+ > + +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
+