Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feed keyboards #298

Merged
merged 10 commits into from
Jan 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ serde_json = "1"
sha2 = "0.10"
typed-builder = "0.11"
url = "2"
uuid = { version = "1.1", features = ["v4"] }

[dev-dependencies]
mockito = "0.31"
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ Available fields:
- guid
- description
- author

/toggle_preview_enabled - disable or enable previews

/get_preview_enabled - check if previews are enabled for the current chat. by default, previews are enabled
```

### Common info
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE telegram_subscriptions DROP COLUMN external_id;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE telegram_subscriptions ADD COLUMN external_id uuid NOT NULL DEFAULT uuid_generate_v4();
CREATE INDEX telegram_subscriptions_external_id ON telegram_subscriptions(external_id);
116 changes: 104 additions & 12 deletions src/bot/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ use diesel::r2d2::PooledConnection;
use diesel::PgConnection;
use frankenstein::Chat;
use frankenstein::ChatType;
use frankenstein::InlineKeyboardButton;
use frankenstein::InlineKeyboardMarkup;
use frankenstein::Message;
use frankenstein::ReplyMarkup;
use frankenstein::SendMessageParams;
use std::str::FromStr;
use typed_builder::TypedBuilder;
use uuid::Uuid;

pub use close::Close;
pub use get_filter::GetFilter;
Expand All @@ -28,7 +32,7 @@ pub use get_timezone::GetTimezone;
pub use help::Help;
pub use help_command_info::HelpCommandInfo;
pub use info::Info;
pub use list_subscriptions::ListSubscriptions;
pub use list_subscriptions_keyboard::ListSubscriptionsKeyboard;
pub use remove_filter::RemoveFilter;
pub use remove_global_filter::RemoveGlobalFilter;
pub use remove_global_template::RemoveGlobalTemplate;
Expand All @@ -39,6 +43,7 @@ pub use set_global_filter::SetGlobalFilter;
pub use set_global_template::SetGlobalTemplate;
pub use set_template::SetTemplate;
pub use set_timezone::SetTimezone;
pub use show_feed_keyboard::ShowFeedKeyboard;
pub use start::Start;
pub use subscribe::Subscribe;
pub use toggle_preview_enabled::TogglePreviewEnabled;
Expand All @@ -55,7 +60,7 @@ pub mod get_timezone;
pub mod help;
pub mod help_command_info;
pub mod info;
pub mod list_subscriptions;
pub mod list_subscriptions_keyboard;
pub mod remove_filter;
pub mod remove_global_filter;
pub mod remove_global_template;
Expand All @@ -66,6 +71,7 @@ pub mod set_global_filter;
pub mod set_global_template;
pub mod set_template;
pub mod set_timezone;
pub mod show_feed_keyboard;
pub mod start;
pub mod subscribe;
pub mod toggle_preview_enabled;
Expand Down Expand Up @@ -115,6 +121,7 @@ pub enum BotCommand {
SetGlobalTemplate(String),
SetTemplate(String),
SetTimezone(String),
ShowFeedKeyboard(String),
Start,
Subscribe(String),
TogglePreviewEnabled,
Expand Down Expand Up @@ -142,7 +149,7 @@ impl FromStr for BotCommand {
let args = parse_args(Unsubscribe::command(), command);

BotCommand::Unsubscribe(args)
} else if command.starts_with(ListSubscriptions::command()) {
} else if command.starts_with(ListSubscriptionsKeyboard::command()) {
BotCommand::ListSubscriptions
} else if command.starts_with(Start::command()) {
BotCommand::Start
Expand Down Expand Up @@ -198,6 +205,10 @@ impl FromStr for BotCommand {
let args = parse_args(SetContentFields::command(), command);

BotCommand::SetContentFields(args)
} else if command.starts_with(ShowFeedKeyboard::command()) {
let args = parse_args(ShowFeedKeyboard::command(), command);

BotCommand::ShowFeedKeyboard(args)
} else if command.starts_with(Close::command()) {
BotCommand::Close
} else if command.starts_with(GetPreviewEnabled::command()) {
Expand Down Expand Up @@ -258,6 +269,21 @@ pub trait Command {
}
}

fn send_message_and_remove(&self, send_message_params: SendMessageParams, message: &Message) {
match self.api().send_message_with_params(&send_message_params) {
Err(error) => {
error!(
"Failed to send a message {:?} {:?}",
error, send_message_params
);
}

Ok(_) => {
self.remove_message(message);
}
}
}

fn send_message(&self, send_message_params: SendMessageParams) {
if let Err(error) = self.api().send_message_with_params(&send_message_params) {
error!(
Expand All @@ -271,6 +297,33 @@ pub trait Command {
self.api().remove_message(message)
}

fn simple_keyboard(&self, message: String, back_command: String, chat_id: i64) -> Response {
let mut buttons: Vec<Vec<InlineKeyboardButton>> = Vec::new();
let mut row: Vec<InlineKeyboardButton> = Vec::new();

let button = InlineKeyboardButton::builder()
.text("◀ Back")
.callback_data(back_command)
.build();

row.push(button);
buttons.push(row);
buttons.push(Close::button_row());

let keyboard = InlineKeyboardMarkup::builder()
.inline_keyboard(buttons)
.build();

let params = SendMessageParams::builder()
.chat_id(chat_id)
.disable_web_page_preview(true)
.text(message)
.reply_markup(ReplyMarkup::InlineKeyboardMarkup(keyboard))
.build();

Response::Params(params)
}

fn fetch_db_connection(
&self,
) -> Result<PooledConnection<ConnectionManager<PgConnection>>, String> {
Expand All @@ -289,11 +342,32 @@ pub trait Command {
}

fn find_subscription(
&self,
db_connection: &mut PgConnection,
chat_id: i64,
feed_url_or_external_id: &str,
) -> Result<(TelegramSubscription, Feed), String> {
match Uuid::from_str(feed_url_or_external_id) {
Ok(uuid) => match telegram::find_subscription_by_external_id(db_connection, uuid) {
Some(subscription) => {
let feed = feeds::find(db_connection, subscription.feed_id).unwrap();

Ok((subscription, feed))
}
None => Err("Subscription does not exist".to_string()),
},
Err(_) => {
self.find_subscription_by_feed_url(db_connection, chat_id, feed_url_or_external_id)
}
}
}

fn find_subscription_by_feed_url(
&self,
db_connection: &mut PgConnection,
chat_id: i64,
feed_url: &str,
) -> Result<TelegramSubscription, String> {
) -> Result<(TelegramSubscription, Feed), String> {
let not_exists_error = Err("Subscription does not exist".to_string());
let feed = self.find_feed(db_connection, feed_url)?;

Expand All @@ -302,17 +376,23 @@ pub trait Command {
None => return not_exists_error,
};

let telegram_subscription = NewTelegramSubscription {
chat_id: chat.id,
feed_id: feed.id,
};

match telegram::find_subscription(db_connection, telegram_subscription) {
Some(subscription) => Ok(subscription),
match self.find_subscription_by_chat_id_and_feed_id(db_connection, chat.id, feed.id) {
Some(subscription) => Ok((subscription, feed)),
None => not_exists_error,
}
}

fn find_subscription_by_chat_id_and_feed_id(
&self,
db_connection: &mut PgConnection,
chat_id: i64,
feed_id: i64,
) -> Option<TelegramSubscription> {
let telegram_subscription = NewTelegramSubscription { chat_id, feed_id };

telegram::find_subscription(db_connection, telegram_subscription)
}

fn find_feed(&self, db_connection: &mut PgConnection, feed_url: &str) -> Result<Feed, String> {
match feeds::find_by_link(db_connection, feed_url) {
Some(feed) => Ok(feed),
Expand All @@ -339,6 +419,7 @@ pub trait Command {
pub struct CommandProcessor {
message: Message,
command: BotCommand,
callback: bool,
}

impl CommandProcessor {
Expand All @@ -355,10 +436,11 @@ impl CommandProcessor {
BotCommand::Unsubscribe(args) => Unsubscribe::builder()
.message(self.message.clone())
.args(args.to_string())
.callback(self.callback)
.build()
.run(),

BotCommand::ListSubscriptions => ListSubscriptions::builder()
BotCommand::ListSubscriptions => ListSubscriptionsKeyboard::builder()
.message(self.message.clone())
.build()
.run(),
Expand All @@ -385,12 +467,14 @@ impl CommandProcessor {
BotCommand::GetFilter(args) => GetFilter::builder()
.message(self.message.clone())
.args(args.to_string())
.callback(self.callback)
.build()
.run(),

BotCommand::RemoveFilter(args) => RemoveFilter::builder()
.message(self.message.clone())
.args(args.to_string())
.callback(self.callback)
.build()
.run(),

Expand All @@ -403,12 +487,14 @@ impl CommandProcessor {
BotCommand::GetTemplate(args) => GetTemplate::builder()
.message(self.message.clone())
.args(args.to_string())
.callback(self.callback)
.build()
.run(),

BotCommand::RemoveTemplate(args) => RemoveTemplate::builder()
.message(self.message.clone())
.args(args.to_string())
.callback(self.callback)
.build()
.run(),

Expand Down Expand Up @@ -475,6 +561,12 @@ impl CommandProcessor {
.message(self.message.clone())
.build()
.run(),

BotCommand::ShowFeedKeyboard(args) => ShowFeedKeyboard::builder()
.message(self.message.clone())
.feed_url_or_external_id(args.to_string())
.build()
.run(),
};
}
}
2 changes: 1 addition & 1 deletion src/bot/commands/close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use frankenstein::InlineKeyboardButton;
use typed_builder::TypedBuilder;

static COMMAND: &str = "/close";
static BUTTON_NAME: &str = "Close";
static BUTTON_NAME: &str = "Close";

#[derive(TypedBuilder)]
pub struct Close {
Expand Down
44 changes: 33 additions & 11 deletions src/bot/commands/get_filter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::Command;
use super::Message;
use super::Response;
use super::ShowFeedKeyboard;
use diesel::PgConnection;
use frankenstein::SendMessageParams;
use typed_builder::TypedBuilder;

static COMMAND: &str = "/get_filter";
Expand All @@ -10,20 +12,38 @@ static COMMAND: &str = "/get_filter";
pub struct GetFilter {
message: Message,
args: String,
callback: bool,
}

impl GetFilter {
pub fn run(&self) {
self.execute(&self.message);
}

fn get_filter(&self, db_connection: &mut PgConnection) -> String {
match self.find_subscription(db_connection, self.message.chat.id, &self.args) {
Err(message) => message,
Ok(subscription) => match subscription.filter_words {
None => "You did not set a filter for this subcription".to_string(),
Some(filter_words) => filter_words.join(", "),
},
fn get_filter(&self, db_connection: &mut PgConnection) -> Response {
let (subscription, _feed) =
match self.find_subscription(db_connection, self.message.chat.id, &self.args) {
Ok(subscription_and_feed) => subscription_and_feed,
Err(error) => return Response::Simple(error),
};

let response = match subscription.filter_words {
None => "You did not set a filter for this subcription".to_string(),
Some(filter_words) => filter_words.join(", "),
};

if self.callback {
self.simple_keyboard(
response,
format!(
"{} {}",
ShowFeedKeyboard::command(),
subscription.external_id
),
self.message.chat.id,
)
} else {
Response::Simple(response)
}
}

Expand All @@ -34,12 +54,14 @@ impl GetFilter {

impl Command for GetFilter {
fn response(&self) -> Response {
let response = match self.fetch_db_connection() {
match self.fetch_db_connection() {
Ok(mut connection) => self.get_filter(&mut connection),

Err(error_message) => error_message,
};
Err(error_message) => Response::Simple(error_message),
}
}

Response::Simple(response)
fn send_message(&self, send_message_params: SendMessageParams) {
self.send_message_and_remove(send_message_params, &self.message);
}
}
Loading