Skip to content

Commit

Permalink
global filters (#214)
Browse files Browse the repository at this point in the history
* global filters

* add commands

* fix clippy

* fix clippy

* remove global template command
  • Loading branch information
ayrat555 committed May 29, 2022
1 parent 4bda16e commit 25cd7a6
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 17 deletions.
1 change: 1 addition & 0 deletions migrations/2022-05-15-162026_add_filter_to_chats/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE telegram_chats DROP COLUMN filter_words;
1 change: 1 addition & 0 deletions migrations/2022-05-15-162026_add_filter_to_chats/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE telegram_chats ADD COLUMN filter_words text[];
14 changes: 14 additions & 0 deletions src/bot/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ 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;
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;
Expand Down Expand Up @@ -149,4 +152,15 @@ pub trait Command {
None => Err("Feed does not exist".to_string()),
}
}

fn parse_filter(&self, params: &str) -> Result<Vec<String>, String> {
let filter_words: Vec<String> =
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)
}
}
50 changes: 50 additions & 0 deletions src/bot/commands/get_global_filter.rs
Original file line number Diff line number Diff line change
@@ -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<ConnectionManager<PgConnection>>, 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<ConnectionManager<PgConnection>>,
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()
}
}
50 changes: 50 additions & 0 deletions src/bot/commands/remove_global_filter.rs
Original file line number Diff line number Diff line change
@@ -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<ConnectionManager<PgConnection>>, 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<ConnectionManager<PgConnection>>,
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()
}
}
12 changes: 5 additions & 7 deletions src/bot/commands/set_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> =
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(),
Expand Down
71 changes: 71 additions & 0 deletions src/bot/commands/set_global_filter.rs
Original file line number Diff line number Diff line change
@@ -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<ConnectionManager<PgConnection>>, 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<ConnectionManager<PgConnection>>,
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()
}
}
9 changes: 9 additions & 0 deletions src/bot/handler.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
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;
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;
Expand Down Expand Up @@ -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()) {
Expand Down
29 changes: 29 additions & 0 deletions src/db/telegram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ pub fn set_global_template(
.get_result::<TelegramChat>(conn)
}

pub fn set_global_filter(
conn: &PgConnection,
chat: &TelegramChat,
filter_words: Option<Vec<String>>,
) -> Result<TelegramChat, Error> {
diesel::update(chat)
.set(telegram_chats::filter_words.eq(filter_words))
.get_result::<TelegramChat>(conn)
}

pub fn set_template(
conn: &PgConnection,
chat: &TelegramSubscription,
Expand Down Expand Up @@ -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();
Expand Down
34 changes: 24 additions & 10 deletions src/deliver/deliver_chat_updates_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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(
Expand Down Expand Up @@ -307,6 +310,17 @@ fn handle_error(error: String, connection: &PgConnection, chat_id: i64) -> Deliv
}
}

fn fetch_filter_words(
chat: &TelegramChat,
subscription: &TelegramSubscription,
) -> Option<Vec<String>> {
if chat.filter_words.is_some() {
return chat.filter_words.clone();
}

subscription.filter_words.clone()
}

fn format_messages(
template: Option<String>,
offset: Option<i32>,
Expand Down
1 change: 1 addition & 0 deletions src/models/telegram_chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ pub struct TelegramChat {
pub title: Option<String>,
pub utc_offset_minutes: Option<i32>,
pub template: Option<String>,
pub filter_words: Option<Vec<String>>,
}
1 change: 1 addition & 0 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ table! {
title -> Nullable<Text>,
utc_offset_minutes -> Nullable<Int4>,
template -> Nullable<Text>,
filter_words -> Nullable<Array<Text>>,
}
}

Expand Down

0 comments on commit 25cd7a6

Please sign in to comment.