diff --git a/migrations/2022-05-15-162026_add_filter_to_chats/down.sql b/migrations/2022-05-15-162026_add_filter_to_chats/down.sql new file mode 100644 index 00000000..427a56f6 --- /dev/null +++ b/migrations/2022-05-15-162026_add_filter_to_chats/down.sql @@ -0,0 +1 @@ +ALTER TABLE telegram_chats DROP COLUMN filter_words; diff --git a/migrations/2022-05-15-162026_add_filter_to_chats/up.sql b/migrations/2022-05-15-162026_add_filter_to_chats/up.sql new file mode 100644 index 00000000..495ee8dc --- /dev/null +++ b/migrations/2022-05-15-162026_add_filter_to_chats/up.sql @@ -0,0 +1 @@ +ALTER TABLE telegram_chats ADD COLUMN filter_words text[]; diff --git a/src/bot/commands.rs b/src/bot/commands.rs index df898536..a76df64e 100644 --- a/src/bot/commands.rs +++ b/src/bot/commands.rs @@ -17,6 +17,7 @@ use frankenstein::SendMessageParams; use frankenstein::TelegramApi; pub mod get_filter; +pub mod get_global_filter; pub mod get_global_template; pub mod get_template; pub mod get_timezone; @@ -24,10 +25,12 @@ pub mod help; pub mod info; pub mod list_subscriptions; pub mod remove_filter; +pub mod remove_global_filter; pub mod remove_global_template; pub mod remove_template; pub mod set_content_fields; pub mod set_filter; +pub mod set_global_filter; pub mod set_global_template; pub mod set_template; pub mod set_timezone; @@ -149,4 +152,15 @@ pub trait Command { None => Err("Feed does not exist".to_string()), } } + + fn parse_filter(&self, params: &str) -> Result, String> { + let filter_words: Vec = + params.split(',').map(|s| s.trim().to_lowercase()).collect(); + + if filter_words.len() > 7 { + return Err("The number of filter words is limited by 7".to_string()); + } + + Ok(filter_words) + } } diff --git a/src/bot/commands/get_global_filter.rs b/src/bot/commands/get_global_filter.rs new file mode 100644 index 00000000..5e0f77c8 --- /dev/null +++ b/src/bot/commands/get_global_filter.rs @@ -0,0 +1,50 @@ +use super::Command; +use super::Message; +use crate::bot::telegram_client::Api; +use crate::db::telegram; +use diesel::r2d2::ConnectionManager; +use diesel::r2d2::Pool; +use diesel::PgConnection; + +static COMMAND: &str = "/get_global_filter"; + +pub struct GetGlobalFilter {} + +impl GetGlobalFilter { + pub fn execute(db_pool: Pool>, api: Api, message: Message) { + Self {}.execute(db_pool, api, message); + } + + fn get_global_template(&self, db_connection: &PgConnection, message: &Message) -> String { + match telegram::find_chat(db_connection, message.chat.id) { + None => "You don't have the global filter set".to_string(), + Some(chat) => match chat.filter_words { + None => "You don't have the global filter set".to_string(), + Some(filter_words) => { + format!("Your global filter is \n {}", filter_words.join(", ")) + } + }, + } + } + + pub fn command() -> &'static str { + COMMAND + } +} + +impl Command for GetGlobalFilter { + fn response( + &self, + db_pool: Pool>, + message: &Message, + ) -> String { + match self.fetch_db_connection(db_pool) { + Ok(connection) => self.get_global_template(&connection, message), + Err(error_message) => error_message, + } + } + + fn command(&self) -> &str { + Self::command() + } +} diff --git a/src/bot/commands/remove_global_filter.rs b/src/bot/commands/remove_global_filter.rs new file mode 100644 index 00000000..a401c349 --- /dev/null +++ b/src/bot/commands/remove_global_filter.rs @@ -0,0 +1,50 @@ +use super::Command; +use super::Message; +use crate::bot::telegram_client::Api; +use crate::db::telegram; +use diesel::r2d2::ConnectionManager; +use diesel::r2d2::Pool; +use diesel::PgConnection; + +static COMMAND: &str = "/remove_global_filter"; + +pub struct RemoveGlobalFilter {} + +impl RemoveGlobalFilter { + pub fn execute(db_pool: Pool>, api: Api, message: Message) { + Self {}.execute(db_pool, api, message); + } + + fn remove_global_filter(&self, db_connection: &PgConnection, message: &Message) -> String { + let chat = match telegram::find_chat(db_connection, message.chat.id) { + Some(chat) => chat, + None => return "You don't have any subcriptions".to_string(), + }; + + match telegram::set_global_filter(db_connection, &chat, None) { + Ok(_) => "The global filter was removed".to_string(), + Err(_) => "Failed to update the filter".to_string(), + } + } + + pub fn command() -> &'static str { + COMMAND + } +} + +impl Command for RemoveGlobalFilter { + fn response( + &self, + db_pool: Pool>, + message: &Message, + ) -> String { + match self.fetch_db_connection(db_pool) { + Ok(connection) => self.remove_global_filter(&connection, message), + Err(error_message) => error_message, + } + } + + fn command(&self) -> &str { + Self::command() + } +} diff --git a/src/bot/commands/set_filter.rs b/src/bot/commands/set_filter.rs index ab9eb706..d817a92f 100644 --- a/src/bot/commands/set_filter.rs +++ b/src/bot/commands/set_filter.rs @@ -31,19 +31,17 @@ impl SetFilter { return "Filter can not be empty".to_string(); } + let filter_words = match self.parse_filter(vec[1]) { + Err(message) => return message, + Ok(words) => words, + }; + let subscription = match self.find_subscription(db_connection, message.chat.id, vec[0].to_string()) { Err(message) => return message, Ok(subscription) => subscription, }; - let filter_words: Vec = - vec[1].split(',').map(|s| s.trim().to_lowercase()).collect(); - - if filter_words.len() > 7 { - return "The number of filter words is limited by 7".to_string(); - } - match telegram::set_filter(db_connection, &subscription, Some(filter_words.clone())) { Ok(_) => format!("The filter was updated:\n\n{}", filter_words.join(", ")), Err(_) => "Failed to update the filter".to_string(), diff --git a/src/bot/commands/set_global_filter.rs b/src/bot/commands/set_global_filter.rs new file mode 100644 index 00000000..979667dd --- /dev/null +++ b/src/bot/commands/set_global_filter.rs @@ -0,0 +1,71 @@ +use super::Command; +use super::Message; +use crate::bot::telegram_client::Api; +use crate::db::telegram; +use diesel::r2d2::ConnectionManager; +use diesel::r2d2::Pool; +use diesel::PgConnection; + +static COMMAND: &str = "/set_global_filter"; + +pub struct SetGlobalFilter {} + +impl SetGlobalFilter { + pub fn execute(db_pool: Pool>, api: Api, message: Message) { + Self {}.execute(db_pool, api, message); + } + + fn set_global_template( + &self, + db_connection: &PgConnection, + message: &Message, + filter: String, + ) -> String { + let chat = match telegram::find_chat(db_connection, message.chat.id) { + Some(chat) => chat, + None => return "You don't have any subcriptions".to_string(), + }; + + if filter.is_empty() { + return "Filter can not be empty".to_string(); + } + + let filter_words = match self.parse_filter(&filter) { + Err(message) => return message, + Ok(words) => words, + }; + + match telegram::set_global_filter(db_connection, &chat, Some(filter_words.clone())) { + Ok(_) => format!( + "The global filter was updated:\n\n{}", + filter_words.join(", ") + ), + Err(_) => "Failed to update the filter".to_string(), + } + } + + pub fn command() -> &'static str { + COMMAND + } +} + +impl Command for SetGlobalFilter { + fn response( + &self, + db_pool: Pool>, + message: &Message, + ) -> 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) + } + Err(error_message) => error_message, + } + } + + fn command(&self) -> &str { + Self::command() + } +} diff --git a/src/bot/handler.rs b/src/bot/handler.rs index a7ddaaca..aa2b4ca0 100644 --- a/src/bot/handler.rs +++ b/src/bot/handler.rs @@ -1,4 +1,5 @@ use super::commands::get_filter::GetFilter; +use super::commands::get_global_filter::GetGlobalFilter; use super::commands::get_global_template::GetGlobalTemplate; use super::commands::get_template::GetTemplate; use super::commands::get_timezone::GetTimezone; @@ -6,10 +7,12 @@ use super::commands::help::Help; use super::commands::info::Info; use super::commands::list_subscriptions::ListSubscriptions; use super::commands::remove_filter::RemoveFilter; +use super::commands::remove_global_filter::RemoveGlobalFilter; use super::commands::remove_global_template::RemoveGlobalTemplate; use super::commands::remove_template::RemoveTemplate; use super::commands::set_content_fields::SetContentFields; use super::commands::set_filter::SetFilter; +use super::commands::set_global_filter::SetGlobalFilter; use super::commands::set_global_template::SetGlobalTemplate; use super::commands::set_template::SetTemplate; use super::commands::set_timezone::SetTimezone; @@ -113,6 +116,12 @@ impl Handler { RemoveGlobalTemplate::execute(db_pool, api, message); } else if command.starts_with(GetGlobalTemplate::command()) { GetGlobalTemplate::execute(db_pool, api, message); + } else if command.starts_with(SetGlobalFilter::command()) { + SetGlobalFilter::execute(db_pool, api, message); + } else if command.starts_with(GetGlobalFilter::command()) { + GetGlobalFilter::execute(db_pool, api, message); + } else if command.starts_with(RemoveGlobalFilter::command()) { + RemoveGlobalFilter::execute(db_pool, api, message); } else if command.starts_with(Info::command()) { Info::execute(db_pool, api, message); } else if command.starts_with(SetContentFields::command()) { diff --git a/src/db/telegram.rs b/src/db/telegram.rs index 870c438e..09a29a3b 100644 --- a/src/db/telegram.rs +++ b/src/db/telegram.rs @@ -76,6 +76,16 @@ pub fn set_global_template( .get_result::(conn) } +pub fn set_global_filter( + conn: &PgConnection, + chat: &TelegramChat, + filter_words: Option>, +) -> Result { + diesel::update(chat) + .set(telegram_chats::filter_words.eq(filter_words)) + .get_result::(conn) +} + pub fn set_template( conn: &PgConnection, chat: &TelegramSubscription, @@ -862,6 +872,25 @@ mod tests { }); } + #[test] + fn set_global_filter_sets_filter() { + let connection = db::establish_test_connection(); + + let new_chat = build_new_chat_with_id(200); + + connection.test_transaction::<(), Error, _>(|| { + let chat = super::create_chat(&connection, new_chat).unwrap(); + let filter = vec!["filter1".to_string(), "filter2".to_string()]; + + let result = + super::set_global_filter(&connection, &chat, Some(filter.clone())).unwrap(); + + assert_eq!(result.filter_words.unwrap(), filter); + + Ok(()) + }); + } + #[test] fn set_template_sets_template() { let connection = db::establish_test_connection(); diff --git a/src/deliver/deliver_chat_updates_job.rs b/src/deliver/deliver_chat_updates_job.rs index b3aedb9b..4509a325 100644 --- a/src/deliver/deliver_chat_updates_job.rs +++ b/src/deliver/deliver_chat_updates_job.rs @@ -94,15 +94,18 @@ impl DeliverChatUpdatesJob { let feed = feeds::find(connection, subscription.feed_id).unwrap(); let chat = telegram::find_chat(connection, chat_id).unwrap(); - - self.maybe_send_unread_messages_count( - subscription, - connection, - feed_items.len() as i64, - feed.link.clone(), - api, - &chat, - )?; + let filter_words = fetch_filter_words(&chat, subscription); + + if filter_words.is_none() { + self.maybe_send_unread_messages_count( + subscription, + connection, + feed_items.len() as i64, + feed.link.clone(), + api, + &chat, + )?; + } if !feed_items.is_empty() { let template = match subscription.template.clone() { @@ -112,7 +115,7 @@ impl DeliverChatUpdatesJob { let messages = format_messages(template, chat.utc_offset_minutes, feed_items, feed); - match subscription.filter_words.clone() { + match filter_words { None => { for (message, publication_date) in messages { self.send_text_message_and_updated_subscription( @@ -307,6 +310,17 @@ fn handle_error(error: String, connection: &PgConnection, chat_id: i64) -> Deliv } } +fn fetch_filter_words( + chat: &TelegramChat, + subscription: &TelegramSubscription, +) -> Option> { + if chat.filter_words.is_some() { + return chat.filter_words.clone(); + } + + subscription.filter_words.clone() +} + fn format_messages( template: Option, offset: Option, diff --git a/src/models/telegram_chat.rs b/src/models/telegram_chat.rs index ca876424..d3526c4d 100644 --- a/src/models/telegram_chat.rs +++ b/src/models/telegram_chat.rs @@ -15,4 +15,5 @@ pub struct TelegramChat { pub title: Option, pub utc_offset_minutes: Option, pub template: Option, + pub filter_words: Option>, } diff --git a/src/schema.rs b/src/schema.rs index caeeb0e3..38526827 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -42,6 +42,7 @@ table! { title -> Nullable, utc_offset_minutes -> Nullable, template -> Nullable, + filter_words -> Nullable>, } }