Skip to content

Commit

Permalink
feed keyboards (#298)
Browse files Browse the repository at this point in the history
* list subscriptions keyboard

* show feed keyboard

* finish keyboards

* fix tests

* fix warning

* remove listsubscriptions

* refactor

* fix long callback data

* add emojis

* fix clippy warnings
  • Loading branch information
ayrat555 authored Jan 29, 2023
1 parent a26d5cb commit fa3f6d3
Show file tree
Hide file tree
Showing 23 changed files with 478 additions and 273 deletions.
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

0 comments on commit fa3f6d3

Please sign in to comment.