diff --git a/lib/telegram_webhook.php b/lib/telegram_webhook.php new file mode 100644 index 0000000000..312a299258 --- /dev/null +++ b/lib/telegram_webhook.php @@ -0,0 +1,86 @@ + $chatId, 'text' => $text])); + Hm_Functions::c_setopt($curl_handle, CURLOPT_HTTPHEADER, ["Content-Type: application/x-www-form-urlencoded"]); + $curl_result = Hm_Functions::c_exec($curl_handle); + if (trim($curl_result)) { + $response_data = json_decode($curl_result, true); + if (!$response_data['ok']) { + Hm_Debug::add("ERRMessage not sent: ".$response_data['description']); + } + } + }else{ + Hm_Debug::add('No chat found, please check your token.'); + } + } + + /** + * get the chat ID using webhook_token + * @param string $webhook_token + */ + public static function get_chat_id($webhook_token) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, static::PREFIX_URI . 'bot' . $webhook_token . '/getUpdates'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $curl_result = curl_exec($ch); + + if ($curl_result === false) { + Hm_Msgs::add('cURL Error: ' . curl_error($ch) . '
'); + curl_close($ch); + return ''; + } + + curl_close($ch); + if (trim($curl_result)) { + $response_data = json_decode($curl_result, true); + // Log the decoded response data for debugging + if (isset($response_data['result'][0]['message']['chat']['id']) && !empty($response_data['result'][0]['message']['chat']['id'])) { + $chatId = $response_data['result'][0]['message']['chat']['id']; + return $chatId; + } else { + Hm_Debug::add('ERRNo messages found. Please send a message to your bot first.
'); + return ''; + } + } + } + + /** + * This function is usefull when trying to resend, we need to delete old webhook before we send a new one + * delete the webhook using webhook_token if there is one + * sometimes the webhook is not deleted, so we need to delete it manually + * and sometines we are gettiting not found error + * @param string $webhook_token + */ + public static function delete_webhook($webhook_token) { + $curl_handle = Hm_Functions::c_init(); + Hm_Functions::c_setopt($curl_handle, CURLOPT_URL, static::PREFIX_URI.'bot'.$webhook_token.'/delete_webhook'); + Hm_Functions::c_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); + Hm_Functions::c_exec($curl_handle); + } +} diff --git a/modules/core/functions.php b/modules/core/functions.php index 5a798c73ee..35da279174 100644 --- a/modules/core/functions.php +++ b/modules/core/functions.php @@ -350,6 +350,20 @@ function max_source_setting_callback($val) { return $val; }} +/** + * Sanitize a default value for interval webhook notifications + * @subpackage core/functions + * @param int $val request interval + * @return sanitized interval + */ +if (!hm_exists('interval_webhook_notification_setting_callback')) { +function interval_webhook_notification_setting_callback($val) { + if ($val < 1) { + return DEFAULT_INTERVAL_WEBHOOK_NOTIFICATION; + } + return $val; +}} + /** * Save user settings from the session to permanent storage * @subpackage core/functions diff --git a/modules/core/handler_modules.php b/modules/core/handler_modules.php index adf089e71c..f2494e5809 100644 --- a/modules/core/handler_modules.php +++ b/modules/core/handler_modules.php @@ -679,6 +679,7 @@ public function process() { } $this->out('mailto_handler', $this->user_config->get('mailto_handler_setting', false)); $this->out('warn_for_unsaved_changes', $this->user_config->get('warn_for_unsaved_changes_setting', false)); + $this->out('telegram_webhook_interval', $this->user_config->get('interval_webhook_notification_setting', false)); $this->out('no_password_save', $this->user_config->get('no_password_save_setting', false)); if (!strstr($this->request->server['REQUEST_URI'], 'page=') && $this->page == 'home') { $start_page = $this->user_config->get('start_page_setting', false); diff --git a/modules/core/modules.php b/modules/core/modules.php index dd980474e8..c16163e9f8 100644 --- a/modules/core/modules.php +++ b/modules/core/modules.php @@ -9,6 +9,7 @@ define('MAX_PER_SOURCE', 1000); define('DEFAULT_PER_SOURCE', 20); define('DEFAULT_MAX_GOOGLE_CONTACTS_NUMBER', 500); +define('DEFAULT_INTERVAL_WEBHOOK_NOTIFICATION', 5); define('DEFAULT_SINCE', '-1 week'); define('DEFAULT_SEARCH_FLD', 'TEXT'); diff --git a/modules/core/output_modules.php b/modules/core/output_modules.php index 81284bbce7..a98dcadd35 100644 --- a/modules/core/output_modules.php +++ b/modules/core/output_modules.php @@ -619,6 +619,7 @@ protected function output() { 'var hm_web_root_path = function() { return "'.WEB_ROOT.'"; };'. 'var hm_flag_image_src = function() { return ""; };'. 'var hm_check_dirty_flag = function() { return '.($this->get('warn_for_unsaved_changes', '') ? '1' : '0').'; };'. + 'var hm_telegram_webhook_interval = function() { return '.$this->get('telegram_webhook_interval', '').'; };'. format_data_sources($this->get('data_sources', array()), $this); if (!$this->get('disable_delete_prompt')) { diff --git a/modules/core/site.js b/modules/core/site.js index d8abb05e50..fa0f84c566 100644 --- a/modules/core/site.js +++ b/modules/core/site.js @@ -1799,6 +1799,24 @@ var reset_default_value_checkbox = function() { } }; +var reset_default_value_input_webhook_token = function() { + let field = this.parentElement.parentElement.querySelector('input[type="text"]'); + const defaultValue = field.getAttribute("data-default-value"); + + if (field.disabled == false) { + this.style.transform = "scaleX(1)"; + this.parentElement.setAttribute("restore_aria_label", hm_trans("Restore current value")); + field.setAttribute("current_value", field.value); + field.value = defaultValue; // Use the default value (which is now an empty string) + field.disabled = true; + } else { + this.style.transform = "scaleX(-1)"; + this.parentElement.setAttribute("restore_aria_label", hm_trans("Restore default value")); + field.value = field.getAttribute("current_value"); + field.disabled = false; + } +}; + var reset_default_value_select = function() { let field = this.parentElement.parentElement.firstChild; let tab_static_default_value = {"inline_message_style" : 0, "smtp_compose_type" : 0, "theme_setting" : 0, @@ -1860,6 +1878,32 @@ var reset_default_value_input = function() { } }; +var reset_default_value_input_interval_webhook_notification = function() { + let field = this.parentElement.parentElement.firstChild; + const defaultValue = this.getAttribute("default-value"); + + if (this.style.transform == "scaleX(1)") { + this.style.transform = "scaleX(-1)"; + this.parentElement.setAttribute("restore_aria_label",hm_trans("Restore default value")) + field.value = field.getAttribute("current_value"); + field.style.backgroundColor = "#fff"; + field.style.pointerEvents = "auto"; + field.style.touchAction = "auto"; + } + else { + this.style.transform = "scaleX(1)"; + this.parentElement.setAttribute("restore_aria_label",hm_trans("Restore current value")); + field.setAttribute("current_value", field.value); + field.value = 5; + if(defaultValue) { + field.value = defaultValue; + } + field.style.backgroundColor = "#eee"; + field.style.pointerEvents = "none"; + field.style.touchAction = "none"; + } +}; + var decrease_servers = function(section) { const element = document.querySelector(`.server_count .${section}_server_count`); const value = parseInt(element.textContent); @@ -1942,6 +1986,8 @@ $(function() { $('.reset_default_value_checkbox').on("click", reset_default_value_checkbox); $('.reset_default_value_select').on("click", reset_default_value_select); $('.reset_default_value_input').on("click", reset_default_value_input); + $('.reset_default_value_input_webhook_token').on("click", reset_default_value_input_webhook_token); + $('.reset_default_value_input_interval_webhook_notification').on("click", reset_default_value_input_interval_webhook_notification); } if (hm_check_dirty_flag()) { @@ -2602,7 +2648,7 @@ const observeMessageTextMutationAndHandleExternalResources = (inline) => { if (mutation.addedNodes.length > 0) { mutation.addedNodes.forEach(function (node) { if (node.classList.contains('msg_text_inner')) { - handleExternalResources(inline); + handleExternalResources(inline); } }); } diff --git a/modules/feeds/hm-feed.php b/modules/feeds/hm-feed.php index e7271a7b6b..78e5ba7eee 100644 --- a/modules/feeds/hm-feed.php +++ b/modules/feeds/hm-feed.php @@ -118,7 +118,7 @@ function get_feed_data($url) { } switch ($type) { case 'curl': - $curl_handle=curl_init(); + $curl_handle = curl_init(); curl_setopt($curl_handle, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36"); curl_setopt($curl_handle, CURLOPT_URL, $url); curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT,15); diff --git a/modules/imap/handler_modules.php b/modules/imap/handler_modules.php index 7f7c3b8c4b..a25ab72fac 100644 --- a/modules/imap/handler_modules.php +++ b/modules/imap/handler_modules.php @@ -1,5 +1,4 @@ out('folder_status', $status); $this->out('imap_unread_data', $msg_list); $this->out('imap_server_ids', $form['imap_server_ids']); + + } + } +} + +class Hm_Handler_send_telegram_webhook extends Hm_Handler_Module { + public function process() { + list($success, $form) = $this->process_form(array('unread_message_count')); + if ($success) { + $webhook_token = $this->user_config->get('webhook_token_setting'); + if ($form['unread_message_count'] && !empty($webhook_token)) { + Hm_Telegram_Webhook::send($form['unread_message_count'], $this->config->get('app_name'), $webhook_token); + } } } } diff --git a/modules/imap/output_modules.php b/modules/imap/output_modules.php index 8462c7736c..9abb68d597 100644 --- a/modules/imap/output_modules.php +++ b/modules/imap/output_modules.php @@ -1124,6 +1124,48 @@ protected function output() { } } +/** + * Option to set the interval webhook notification for the settings page + * @subpackage imap/output + */ +class Hm_Output_interval_webhook_notification_setting extends Hm_Output_Module { + protected function output() { + $settings = $this->get('user_settings', array()); + $per_page = 5; + $reset = ''; + if (array_key_exists('interval_webhook_notification', $settings)) { + $per_page = $settings['interval_webhook_notification']; + } + if ($per_page != 5) { + $reset = ''; + } + return ''.$reset.''; + } +} + +/** + * Option to set the webhook token for the settings page + * @subpackage imap/output + */ +class Hm_Output_webhook_token_setting extends Hm_Output_Module { + protected function output() { + $settings = $this->get('user_settings', array()); + $webhook_token = ''; + $reset = ''; + if (array_key_exists('webhook_token', $settings)) { + $webhook_token = $settings['webhook_token']; + } + if (!empty($webhook_token)) { + $reset = ''; + } + return ''.$reset.''; + } +} + /** * Option to set number of google contacts * @subpackage imap/output diff --git a/modules/imap/setup.php b/modules/imap/setup.php index 70ab9da977..9e5415ce0e 100644 --- a/modules/imap/setup.php +++ b/modules/imap/setup.php @@ -37,6 +37,8 @@ add_handler('settings', 'process_enable_simple_download_options', true, 'imap', 'date', 'after'); add_handler('settings', 'process_unread_on_open', true, 'imap', 'date', 'after'); add_handler('settings', 'process_imap_per_page_setting', true, 'imap', 'date', 'after'); +add_handler('settings', 'process_webhook_token_setting', true, 'imap', 'save_user_settings', 'before'); +add_handler('settings', 'process_interval_webhook_notification_setting', true, 'imap', 'date', 'after'); add_handler('settings', 'process_max_google_contacts_number', true, 'imap', 'date', 'after'); add_handler('settings', 'process_review_sent_email_setting', true, 'imap', 'date', 'after'); add_handler('settings', 'process_auto_advance_email_setting', true, 'imap', 'date', 'after'); @@ -51,6 +53,8 @@ add_output('settings', 'imap_pagination_links', true, 'imap', 'imap_msg_icons_setting', 'after'); add_output('settings', 'imap_unread_on_open', true, 'imap', 'imap_msg_icons_setting', 'after'); add_output('settings', 'imap_per_page_setting', true, 'imap', 'imap_pagination_links', 'after'); +add_output('settings', 'webhook_token_setting', true, 'imap', 'imap_per_page_setting', 'after'); +add_output('settings', 'interval_webhook_notification_setting', true, 'imap', 'webhook_token_setting', 'after'); add_output('settings', 'enable_simple_download_options', true, 'imap', 'imap_per_page_setting', 'after'); add_output('settings', 'max_google_contacts_number', true, 'imap', 'imap_per_page_setting', 'after'); add_output('settings', 'review_sent_email', true, 'imap', 'imap_pagination_links', 'after'); @@ -172,6 +176,9 @@ add_handler('ajax_imap_unread', 'save_imap_cache', true); add_output('ajax_imap_unread', 'filter_unread_data', true); +setup_base_ajax_page('ajax_send_telegram_webhook', 'core'); +add_handler('ajax_send_telegram_webhook', 'send_telegram_webhook', true, 'imap'); + /* ajax add/remove to combined view */ setup_base_ajax_page('ajax_imap_update_combined_source', 'core'); add_handler('ajax_imap_update_combined_source', 'load_imap_servers_from_config', true); @@ -331,6 +338,7 @@ 'ajax_imap_unsnooze', 'ajax_imap_junk', 'message_source', + 'ajax_send_telegram_webhook', ), 'allowed_output' => array( @@ -416,6 +424,9 @@ 'review_sent_email' => FILTER_VALIDATE_BOOLEAN, 'imap_snooze_ids' => FILTER_DEFAULT, 'imap_snooze_until' => FILTER_DEFAULT, - 'auto_advance_email' => FILTER_VALIDATE_BOOLEAN + 'auto_advance_email' => FILTER_VALIDATE_BOOLEAN, + 'webhook_token' => FILTER_DEFAULT, + 'interval_webhook_notification' => FILTER_VALIDATE_INT, + 'unread_message_count' => FILTER_VALIDATE_INT, ) ); diff --git a/modules/imap/site.js b/modules/imap/site.js index 711c36b530..f253797890 100644 --- a/modules/imap/site.js +++ b/modules/imap/site.js @@ -1134,6 +1134,15 @@ var imap_unsnooze_messages = function() { ); } +var imap_send_telegram_webhook = function() { + Hm_Ajax.request( + [{'name': 'hm_ajax_hook', 'value': 'ajax_send_telegram_webhook'}, + {'name': 'unread_message_count', 'value': Number.parseInt($('.total_unread_count').text())} + ], + function() {}, + ); +} + if (hm_list_path() == 'sent') { Hm_Message_List.page_caches.sent = 'formatted_sent_data'; } @@ -1190,6 +1199,7 @@ $(function() { if (hm_is_logged()) { imap_unsnooze_messages(); setInterval(imap_unsnooze_messages, 60000); + setInterval(imap_send_telegram_webhook, 60000 * hm_telegram_webhook_interval()); } if ($('.imap_move').length > 0) { diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php index 46796714e7..584b44cde4 100644 --- a/tests/phpunit/bootstrap.php +++ b/tests/phpunit/bootstrap.php @@ -24,6 +24,7 @@ /* get the framework */ require APP_PATH.'lib/framework.php'; +require APP_PATH.'lib/telegram_webhook.php'; /* get the stubs */ require APP_PATH.'tests/phpunit/stubs.php'; diff --git a/tests/phpunit/modules/core/output_modules.php b/tests/phpunit/modules/core/output_modules.php index 71d404263e..ec0e377423 100644 --- a/tests/phpunit/modules/core/output_modules.php +++ b/tests/phpunit/modules/core/output_modules.php @@ -444,10 +444,10 @@ public function test_js_data() { $test = new Output_Test('js_data', 'core'); $test->handler_response = array('disable_delete_prompt' => true); $res = $test->run(); - $this->assertStringStartsWith('