From 5231265c538e947efa182ac3a202feaead4407e6 Mon Sep 17 00:00:00 2001 From: athulkrishnaaei Date: Sat, 27 Aug 2022 23:15:53 +0530 Subject: [PATCH 1/3] Enable html in templates (#241) Co-authored-by: Ayrat Badykov --- Cargo.toml | 2 +- src/bot/commands.rs | 27 +++++++++------------ src/bot/commands/get_filter.rs | 1 + src/bot/commands/get_global_filter.rs | 1 + src/bot/commands/get_global_template.rs | 1 + src/bot/commands/get_template.rs | 1 + src/bot/commands/get_timezone.rs | 1 + src/bot/commands/help.rs | 1 + src/bot/commands/info.rs | 3 ++- src/bot/commands/list_subscriptions.rs | 1 + src/bot/commands/remove_filter.rs | 1 + src/bot/commands/remove_global_filter.rs | 1 + src/bot/commands/remove_global_template.rs | 1 + src/bot/commands/remove_template.rs | 1 + src/bot/commands/set_content_fields.rs | 3 ++- src/bot/commands/set_filter.rs | 1 + src/bot/commands/set_global_filter.rs | 1 + src/bot/commands/set_global_template.rs | 15 +++++++----- src/bot/commands/set_template.rs | 15 +++++++----- src/bot/commands/set_timezone.rs | 1 + src/bot/commands/start.rs | 1 + src/bot/commands/subscribe.rs | 1 + src/bot/commands/unknown_command.rs | 3 ++- src/bot/commands/unsubscribe.rs | 1 + src/bot/telegram_client.rs | 28 ++++++++++++++++++---- src/deliver/render_message.rs | 15 ++++++++++-- 26 files changed, 90 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5d776ce..5b2b2869 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "el_monitorro" version = "0.9.0" authors = ["Ayrat Badykov "] -edition = "2018" +edition = "2021" rust-version = "1.62" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/bot/commands.rs b/src/bot/commands.rs index a76df64e..f3fc7391 100644 --- a/src/bot/commands.rs +++ b/src/bot/commands.rs @@ -13,8 +13,6 @@ use diesel::PgConnection; use frankenstein::Chat; use frankenstein::ChatType; use frankenstein::Message; -use frankenstein::SendMessageParams; -use frankenstein::TelegramApi; pub mod get_filter; pub mod get_global_filter; @@ -60,8 +58,12 @@ impl From for NewTelegramChat { } pub trait Command { - fn response(&self, db_pool: Pool>, message: &Message) - -> String; + fn response( + &self, + db_pool: Pool>, + message: &Message, + api: &Api, + ) -> String; fn execute(&self, db_pool: Pool>, api: Api, message: Message) { info!( @@ -70,23 +72,16 @@ pub trait Command { message.text.as_ref().unwrap() ); - let text = self.response(db_pool, &message); + let text = self.response(db_pool, &message, &api); self.reply_to_message(api, message, text) } fn reply_to_message(&self, api: Api, message: Message, text: String) { - let send_message_params = SendMessageParams::builder() - .chat_id(message.chat.id) - .text(text) - .reply_to_message_id(message.message_id) - .build(); - - if let Err(err) = api.send_message(&send_message_params) { - error!( - "Failed to send a message {:?}: {:?}", - err, send_message_params - ); + if let Err(error) = + api.reply_with_text_message(message.chat.id, text, Some(message.message_id)) + { + error!("Failed to reply to update {:?} {:?}", error, message); } } diff --git a/src/bot/commands/get_filter.rs b/src/bot/commands/get_filter.rs index 84c8a0a1..7d100a98 100644 --- a/src/bot/commands/get_filter.rs +++ b/src/bot/commands/get_filter.rs @@ -39,6 +39,7 @@ impl Command for GetFilter { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/get_global_filter.rs b/src/bot/commands/get_global_filter.rs index 5e0f77c8..d5c01957 100644 --- a/src/bot/commands/get_global_filter.rs +++ b/src/bot/commands/get_global_filter.rs @@ -37,6 +37,7 @@ impl Command for GetGlobalFilter { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.get_global_template(&connection, message), diff --git a/src/bot/commands/get_global_template.rs b/src/bot/commands/get_global_template.rs index 24245c35..efa0e5af 100644 --- a/src/bot/commands/get_global_template.rs +++ b/src/bot/commands/get_global_template.rs @@ -35,6 +35,7 @@ impl Command for GetGlobalTemplate { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.get_global_template(&connection, message), diff --git a/src/bot/commands/get_template.rs b/src/bot/commands/get_template.rs index 98e28f29..2a7d60fd 100644 --- a/src/bot/commands/get_template.rs +++ b/src/bot/commands/get_template.rs @@ -39,6 +39,7 @@ impl Command for GetTemplate { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/get_timezone.rs b/src/bot/commands/get_timezone.rs index 49de28d5..2555cfd8 100644 --- a/src/bot/commands/get_timezone.rs +++ b/src/bot/commands/get_timezone.rs @@ -35,6 +35,7 @@ impl Command for GetTimezone { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.get_timezone(&connection, message), diff --git a/src/bot/commands/help.rs b/src/bot/commands/help.rs index 80b8ea80..347f6010 100644 --- a/src/bot/commands/help.rs +++ b/src/bot/commands/help.rs @@ -57,6 +57,7 @@ impl Command for Help { &self, _db_pool: Pool>, _message: &Message, + _api: &Api, ) -> String { HELP.to_string() } diff --git a/src/bot/commands/info.rs b/src/bot/commands/info.rs index 60f578cc..2d98f657 100644 --- a/src/bot/commands/info.rs +++ b/src/bot/commands/info.rs @@ -73,7 +73,7 @@ impl Command for Info { message.text.as_ref().unwrap() ); - let text = self.response(db_pool, &message); + let text = self.response(db_pool, &message, &api); self.reply_to_message(api, message, text) } else { @@ -87,6 +87,7 @@ impl Command for Info { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.info(&connection, message), diff --git a/src/bot/commands/list_subscriptions.rs b/src/bot/commands/list_subscriptions.rs index 737be7f8..13ee1610 100644 --- a/src/bot/commands/list_subscriptions.rs +++ b/src/bot/commands/list_subscriptions.rs @@ -42,6 +42,7 @@ impl Command for ListSubscriptions { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.list_subscriptions(&connection, message), diff --git a/src/bot/commands/remove_filter.rs b/src/bot/commands/remove_filter.rs index 3c9ed0d5..2bfc6b01 100644 --- a/src/bot/commands/remove_filter.rs +++ b/src/bot/commands/remove_filter.rs @@ -42,6 +42,7 @@ impl Command for RemoveFilter { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/remove_global_filter.rs b/src/bot/commands/remove_global_filter.rs index a401c349..3f27547d 100644 --- a/src/bot/commands/remove_global_filter.rs +++ b/src/bot/commands/remove_global_filter.rs @@ -37,6 +37,7 @@ impl Command for RemoveGlobalFilter { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.remove_global_filter(&connection, message), diff --git a/src/bot/commands/remove_global_template.rs b/src/bot/commands/remove_global_template.rs index 08e43c55..4db24200 100644 --- a/src/bot/commands/remove_global_template.rs +++ b/src/bot/commands/remove_global_template.rs @@ -37,6 +37,7 @@ impl Command for RemoveGlobalTemplate { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => self.remove_global_template(&connection, message), diff --git a/src/bot/commands/remove_template.rs b/src/bot/commands/remove_template.rs index 0f5a1275..47cc996d 100644 --- a/src/bot/commands/remove_template.rs +++ b/src/bot/commands/remove_template.rs @@ -42,6 +42,7 @@ impl Command for RemoveTemplate { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/set_content_fields.rs b/src/bot/commands/set_content_fields.rs index 0b1c3d89..636cbddb 100644 --- a/src/bot/commands/set_content_fields.rs +++ b/src/bot/commands/set_content_fields.rs @@ -77,7 +77,7 @@ impl Command for SetContentFields { message.text.as_ref().unwrap() ); - let text = self.response(db_pool, &message); + let text = self.response(db_pool, &message, &api); self.reply_to_message(api, message, text) } else { @@ -91,6 +91,7 @@ impl Command for SetContentFields { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/set_filter.rs b/src/bot/commands/set_filter.rs index 3ac941c5..6d99eccd 100644 --- a/src/bot/commands/set_filter.rs +++ b/src/bot/commands/set_filter.rs @@ -58,6 +58,7 @@ impl Command for SetFilter { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/set_global_filter.rs b/src/bot/commands/set_global_filter.rs index 979667dd..b817a8e4 100644 --- a/src/bot/commands/set_global_filter.rs +++ b/src/bot/commands/set_global_filter.rs @@ -54,6 +54,7 @@ impl Command for SetGlobalFilter { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/set_global_template.rs b/src/bot/commands/set_global_template.rs index c7b56ce8..42ab8294 100644 --- a/src/bot/commands/set_global_template.rs +++ b/src/bot/commands/set_global_template.rs @@ -18,6 +18,7 @@ impl SetGlobalTemplate { fn set_global_template( &self, + api: &Api, db_connection: &PgConnection, message: &Message, template: String, @@ -32,15 +33,16 @@ impl SetGlobalTemplate { }; let example = match render_template_example(&template) { - Ok(example) => example, + Ok(example) => format!("Your messages will look like:\n\n{}", example), Err(_) => return "The template is invalid".to_string(), }; + if api.send_text_message(message.chat.id, example).is_err() { + return "The template is invalid".to_string(); + } + match telegram::set_global_template(db_connection, &chat, Some(template)) { - Ok(_) => format!( - "The global template was updated. Your messages will look like:\n\n{}", - example - ), + Ok(_) => "The global template was updated".to_string(), Err(_) => "Failed to update the template".to_string(), } } @@ -55,12 +57,13 @@ impl Command for SetGlobalTemplate { &self, db_pool: Pool>, message: &Message, + api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { let text = message.text.as_ref().unwrap(); let argument = self.parse_argument(text); - self.set_global_template(&connection, message, argument) + self.set_global_template(api, &connection, message, argument) } Err(error_message) => error_message, } diff --git a/src/bot/commands/set_template.rs b/src/bot/commands/set_template.rs index 0b87a243..de3af392 100644 --- a/src/bot/commands/set_template.rs +++ b/src/bot/commands/set_template.rs @@ -18,6 +18,7 @@ impl SetTemplate { fn set_template( &self, + api: &Api, db_connection: &PgConnection, message: &Message, params: String, @@ -41,15 +42,16 @@ impl SetTemplate { }; let example = match render_template_example(template) { - Ok(example) => example, + Ok(example) => format!("Your messages will look like:\n\n{}", example), Err(_) => return "The template is invalid".to_string(), }; + if api.send_text_message(message.chat.id, example).is_err() { + return "The template is invalid".to_string(); + } + match telegram::set_template(db_connection, &subscription, Some(template.to_string())) { - Ok(_) => format!( - "The template was updated. Your messages will look like:\n\n{}", - example - ), + Ok(_) => "The template was updated".to_string(), Err(_) => "Failed to update the template".to_string(), } } @@ -64,12 +66,13 @@ impl Command for SetTemplate { &self, db_pool: Pool>, message: &Message, + api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { let text = message.text.as_ref().unwrap(); let argument = self.parse_argument(text); - self.set_template(&connection, message, argument) + self.set_template(api, &connection, message, argument) } Err(error_message) => error_message, } diff --git a/src/bot/commands/set_timezone.rs b/src/bot/commands/set_timezone.rs index 3ce83f91..2ae81e45 100644 --- a/src/bot/commands/set_timezone.rs +++ b/src/bot/commands/set_timezone.rs @@ -73,6 +73,7 @@ impl Command for SetTimezone { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/start.rs b/src/bot/commands/start.rs index 26200b63..f0be86aa 100644 --- a/src/bot/commands/start.rs +++ b/src/bot/commands/start.rs @@ -35,6 +35,7 @@ impl Command for Start { &self, _db_pool: Pool>, _message: &Message, + _api: &Api, ) -> String { START.to_string() } diff --git a/src/bot/commands/subscribe.rs b/src/bot/commands/subscribe.rs index 11c484fd..457e152a 100644 --- a/src/bot/commands/subscribe.rs +++ b/src/bot/commands/subscribe.rs @@ -141,6 +141,7 @@ impl Command for Subscribe { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/commands/unknown_command.rs b/src/bot/commands/unknown_command.rs index 724324d0..25b2266a 100644 --- a/src/bot/commands/unknown_command.rs +++ b/src/bot/commands/unknown_command.rs @@ -28,6 +28,7 @@ impl Command for UnknownCommand { &self, _db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match message.chat.type_field { ChatType::Private => UNKNOWN_COMMAND_PRIVATE.to_string(), @@ -53,7 +54,7 @@ impl Command for UnknownCommand { ); } - let text = self.response(db_pool, &message); + let text = self.response(db_pool, &message, &api); if !text.is_empty() { self.reply_to_message(api, message, text); diff --git a/src/bot/commands/unsubscribe.rs b/src/bot/commands/unsubscribe.rs index 2d7c0436..e7bf80bf 100644 --- a/src/bot/commands/unsubscribe.rs +++ b/src/bot/commands/unsubscribe.rs @@ -75,6 +75,7 @@ impl Command for Unsubscribe { &self, db_pool: Pool>, message: &Message, + _api: &Api, ) -> String { match self.fetch_db_connection(db_pool) { Ok(connection) => { diff --git a/src/bot/telegram_client.rs b/src/bot/telegram_client.rs index cbb2eb44..d4ed60f7 100644 --- a/src/bot/telegram_client.rs +++ b/src/bot/telegram_client.rs @@ -2,6 +2,7 @@ use crate::config::Config; use frankenstein::AllowedUpdate; use frankenstein::ErrorResponse; use frankenstein::GetUpdatesParams; +use frankenstein::ParseMode; use frankenstein::SendMessageParams; use frankenstein::TelegramApi; use frankenstein::Update; @@ -78,10 +79,29 @@ impl Api { } pub fn send_text_message(&self, chat_id: i64, message: String) -> Result<(), Error> { - let send_message_params = SendMessageParams::builder() - .chat_id(chat_id) - .text(message) - .build(); + self.reply_with_text_message(chat_id, message, None) + } + + pub fn reply_with_text_message( + &self, + chat_id: i64, + message: String, + message_id: Option, + ) -> Result<(), Error> { + let send_message_params = match message_id { + None => SendMessageParams::builder() + .chat_id(chat_id) + .text(message) + .parse_mode(ParseMode::Html) + .build(), + + Some(message_id_value) => SendMessageParams::builder() + .chat_id(chat_id) + .text(message) + .parse_mode(ParseMode::Html) + .reply_to_message_id(message_id_value) + .build(), + }; match self.send_message(&send_message_params) { Ok(_) => Ok(()), diff --git a/src/deliver/render_message.rs b/src/deliver/render_message.rs index e4e14438..fdac35b9 100644 --- a/src/deliver/render_message.rs +++ b/src/deliver/render_message.rs @@ -21,12 +21,19 @@ const BOT_ITEM_LINK: &str = "bot_item_link"; const BOT_ITEM_DESCRIPTION: &str = "bot_item_description"; const SUBSTRING_HELPER: &str = "substring"; +const CREATE_LINK_HELPER: &str = "create_link"; +const BOLD_HELPER: &str = "bold"; +const ITALIC_HELPER: &str = "italic"; + const DEFAULT_TEMPLATE: &str = "{{bot_feed_name}}\n\n{{bot_item_name}}\n\n{{bot_item_description}}\n\n{{bot_date}}\n\n{{bot_item_link}}\n\n"; const MAX_CHARS: usize = 4000; const RENDER_ERROR: &str = "Failed to render template"; const EMPTY_MESSAGE_ERROR: &str = "According to your template the message is empty. Telegram doesn't support empty messages. That's why we're sending this placeholder message."; +handlebars_helper!(create_link: |string: String, link: String| format!("{}", link, string)); +handlebars_helper!(bold: |string: String| format!("{}", string)); +handlebars_helper!(italic: |string: String| format!("{}", string)); handlebars_helper!(substring: |string: String, length: usize| truncate(&string, length)); #[derive(Builder)] @@ -78,7 +85,11 @@ impl MessageRenderer { ); let mut reg = Handlebars::new(); + reg.register_helper(SUBSTRING_HELPER, Box::new(substring)); + reg.register_helper(BOLD_HELPER, Box::new(bold)); + reg.register_helper(ITALIC_HELPER, Box::new(italic)); + reg.register_helper(CREATE_LINK_HELPER, Box::new(create_link)); match reg.render_template(&template, &data) { Err(error) => { @@ -137,8 +148,8 @@ pub fn render_template_example(template: &str) -> Result { .bot_feed_name(Some("feed_name".to_string())) .bot_item_name(Some("item_name".to_string())) .bot_date(Some(Utc::now().round_subsecs(0))) - .bot_feed_link(Some("feed_link".to_string())) - .bot_item_link(Some("item_link".to_string())) + .bot_feed_link(Some("https://www.badykov.com/feed.xml".to_string())) + .bot_item_link(Some("https://www.badykov.com/".to_string())) .bot_item_description(Some("item_description".to_string())) .template(Some(template.to_string())) .build(); From 94cdc136b9dd2a3dbbee8d80fba83a6332f09021 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Sun, 28 Aug 2022 10:02:30 +0300 Subject: [PATCH 2/3] replace <3 with emoji Telegram can not recogize it --- src/deliver/render_message.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/deliver/render_message.rs b/src/deliver/render_message.rs index fdac35b9..a5355b20 100644 --- a/src/deliver/render_message.rs +++ b/src/deliver/render_message.rs @@ -123,7 +123,7 @@ impl MessageRenderer { fn maybe_remove_html(&self, value_option: &Option) -> Option { if let Some(value) = value_option { - let without_html = remove_html(value.clone()); + let without_html = remove_html(&value); return Some(without_html); } @@ -197,6 +197,7 @@ fn remove_empty_characters(string: &str) -> String { result.replace(HTML_SPACE, "") } -fn remove_html(string_with_maybe_html: String) -> String { - nanohtml2text::html2text(&string_with_maybe_html) +fn remove_html(string_with_maybe_html: &str) -> String { + let message_without_heart = string_with_maybe_html.replace("<3", "❤️"); + nanohtml2text::html2text(&message_without_heart) } From 232c1e2ed2e979198d1d160c8fcad6bd7c259845 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Sun, 28 Aug 2022 10:11:08 +0300 Subject: [PATCH 3/3] fix clippy --- src/deliver/render_message.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deliver/render_message.rs b/src/deliver/render_message.rs index a5355b20..5539e9a5 100644 --- a/src/deliver/render_message.rs +++ b/src/deliver/render_message.rs @@ -123,7 +123,7 @@ impl MessageRenderer { fn maybe_remove_html(&self, value_option: &Option) -> Option { if let Some(value) = value_option { - let without_html = remove_html(&value); + let without_html = remove_html(value); return Some(without_html); }