diff --git a/Cargo.lock b/Cargo.lock index 601330f..e47109c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,6 +157,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dptree" version = "0.3.0" @@ -347,6 +353,7 @@ dependencies = [ name = "godette" version = "0.1.0" dependencies = [ + "dotenv", "lazy_static", "log", "pretty_env_logger", diff --git a/Cargo.toml b/Cargo.toml index b946206..dcc23fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ log = "0.4" pretty_env_logger = "0.4" tokio = { version = "1.8", features = ["rt-multi-thread", "macros"] } lazy_static = "1.4.0" -url = "2.3.1" \ No newline at end of file +url = "2.3.1" +dotenv = "0.15.0" \ No newline at end of file diff --git a/src/godette.rs b/src/godette.rs index b607aea..6f1b0b3 100644 --- a/src/godette.rs +++ b/src/godette.rs @@ -1,17 +1,18 @@ -use teloxide::{ - prelude::*, - types::{InlineKeyboardButton, InlineKeyboardMarkup}, -}; +use teloxide::{dispatching::DpHandlerDescription, prelude::*, RequestError}; pub mod commands; +mod dispatchers; mod handlers; mod utils; -use commands::{AdminCommand, Command}; -use url::Url; -use utils::get_text_or_empty; pub struct Godette { pub bot: Bot, + pub triggers: Vec, +} + +pub struct Trigger { + pub words: Vec, + pub callback: fn(&Bot, &Message) -> ResponseResult<()>, } pub struct KarmaTrigger { @@ -31,87 +32,36 @@ impl Godette { pub fn new() -> Godette { Godette { bot: Bot::from_env(), + triggers: vec![], } } - pub async fn commands_dispatcher(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> { - match cmd { - Command::Help => handlers::show_help(bot, msg).await?, - Command::Me(quote) => handlers::me(bot, msg, quote).await?, - }; - Ok(()) - } - - pub async fn admin_dispatcher(bot: Bot, msg: Message, cmd: AdminCommand) -> ResponseResult<()> { - let mut is_admin = true; - if msg.chat.is_group() || msg.chat.is_supergroup() { - let sender = msg.from().unwrap(); - let admins = bot.get_chat_administrators(msg.chat.id).await?; - is_admin = admins.iter().any(|member| member.user.id == sender.id); - } - if !is_admin { - return Ok(()); - } - match cmd { - AdminCommand::HelpAdmin => handlers::show_adminhelp(bot, msg).await?, - AdminCommand::Say(quote) => handlers::say(bot, msg, quote).await?, - AdminCommand::Warn(reason) => handlers::warn(bot, msg, reason).await?, - AdminCommand::Unwarn => handlers::unwarn(bot, msg).await?, - }; - Ok(()) - } - - pub async fn message_dispatcher(bot: Bot, msg: Message) -> ResponseResult<()> { - // Checking if it's a reply - let reply = msg.reply_to_message(); - match reply { - Some(reply) => { - Godette::reply_dispatcher(bot.clone(), msg.clone(), reply.to_owned()).await? - } - None => (), - }; - let text = utils::get_text_or_empty(&msg).to_lowercase(); - match text.find("оффтоп") { - Some(_) => { - bot.send_message(msg.chat.id, "Вот вам ссылка на оффтоп") - .reply_to_message_id(msg.id) - .reply_markup(Godette::make_offtop_keyboard()) - .await?; - } - None => (), - } - - Ok(()) - } - - pub async fn reply_dispatcher(bot: Bot, msg: Message, reply: Message) -> ResponseResult<()> { - let triggers = vec![ - KarmaTrigger::new("спс", 1), - KarmaTrigger::new("спасибо", 1), - KarmaTrigger::new("+", 1), - KarmaTrigger::new("благодарю", 1), - KarmaTrigger::new("пасиб", 1), - KarmaTrigger::new("-", -1), - KarmaTrigger::new("👍", 1), - KarmaTrigger::new("👎", -1), - ]; - let text = get_text_or_empty(&msg); - println!("{:?}", text); - for trigger in triggers { - match text.to_lowercase().find(&trigger.text) { - Some(_id) => { - println!("It's a thanks!"); - return handlers::karma(&bot, &msg, &reply, trigger.value).await; - } - None => (), - } - } - Ok(()) - } - - fn make_offtop_keyboard() -> InlineKeyboardMarkup { - let link = Url::parse("https://t.me/Godot_Engine_Offtop").unwrap(); - let button = InlineKeyboardButton::url("Godot Engine оффтоп чат".to_owned(), link); - return InlineKeyboardMarkup::new(vec![[button]]); + pub fn create_handler( + &self, + ) -> Handler<'static, DependencyMap, Result<(), RequestError>, DpHandlerDescription> { + Update::filter_message() + // User commands + .branch( + dptree::entry() + .filter_command::() + .endpoint(Godette::commands_dispatcher), + ) + // Admin commands + .branch( + dptree::entry() + .filter_command::() + .endpoint(Godette::admin_dispatcher), + ) + // Replies + // .branch(Message::filter_reply_to_message().endpoint(Godette::reply_dispatcher)) + // Messages + .branch( + dptree::filter(|msg: Message| { + msg.from() + .map(|user| user.id == UserId(60441930)) + .unwrap_or_default() + }) + .endpoint(Godette::message_dispatcher), + ) } } diff --git a/src/godette/dispatchers.rs b/src/godette/dispatchers.rs new file mode 100644 index 0000000..e9a4471 --- /dev/null +++ b/src/godette/dispatchers.rs @@ -0,0 +1,58 @@ +use teloxide::prelude::*; + +use super::{handlers, utils, Godette, KarmaTrigger, Trigger}; +use crate::commands::{AdminCommand, Command}; + +impl Godette { + pub async fn commands_dispatcher(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> { + match cmd { + Command::Help => handlers::show_help(bot, msg).await?, + Command::Me(quote) => handlers::me(bot, msg, quote).await?, + }; + Ok(()) + } + + pub async fn admin_dispatcher(bot: Bot, msg: Message, cmd: AdminCommand) -> ResponseResult<()> { + let mut is_admin = true; + if msg.chat.is_group() || msg.chat.is_supergroup() { + let sender = msg.from().unwrap(); + let admins = bot.get_chat_administrators(msg.chat.id).await?; + is_admin = admins.iter().any(|member| member.user.id == sender.id); + } + if !is_admin { + return Ok(()); + } + match cmd { + AdminCommand::HelpAdmin => handlers::show_adminhelp(bot, msg).await?, + AdminCommand::Say(quote) => handlers::say(bot, msg, quote).await?, + AdminCommand::Warn(reason) => handlers::warn(bot, msg, reason).await?, + AdminCommand::Unwarn => handlers::unwarn(bot, msg).await?, + }; + Ok(()) + } + + pub async fn message_dispatcher(bot: Bot, msg: Message) -> ResponseResult<()> { + // Checking if it's a reply and send it to Reply dispatcher + let reply = msg.reply_to_message(); + match reply { + Some(reply) => { + Godette::reply_dispatcher(bot.clone(), msg.clone(), reply.to_owned()).await? + } + None => (), + }; + let text = utils::get_text_or_empty(&msg).to_lowercase(); + match text.find("оффтоп") { + Some(_) => handlers::offtop(&bot, &msg).await?, + None => (), + } + + Ok(()) + } + + pub async fn reply_dispatcher(bot: Bot, msg: Message, reply: Message) -> ResponseResult<()> { + let text = utils::get_text_or_empty(&msg); + handlers::karma(&bot, &msg, &reply, &text).await?; + + Ok(()) + } +} diff --git a/src/godette/handlers.rs b/src/godette/handlers.rs index 5e8aa3d..10bc9a4 100644 --- a/src/godette/handlers.rs +++ b/src/godette/handlers.rs @@ -8,6 +8,8 @@ use teloxide::{ use crate::commands::{AdminCommand, Command}; +use super::{utils, KarmaTrigger}; + pub async fn show_help(bot: Bot, msg: Message) -> ResponseResult { bot.send_message(msg.chat.id, Command::descriptions().to_string()) .await @@ -67,22 +69,48 @@ pub async fn unwarn(bot: Bot, msg: Message) -> ResponseResult { .await } -pub async fn karma(bot: &Bot, msg: &Message, reply: &Message, change: i8) -> ResponseResult<()> { - let giver = msg.from().unwrap(); - let reciever = reply.from().unwrap(); - let change_text = match change { - 1 => "повысил", - -1 => "понизил", - _ => "изменил", - }; - let text = format!( - "*{}* {} карму *{}*", - escape(&giver.first_name), - change_text, - escape(&reciever.first_name) - ); - bot.send_message(msg.chat.id, text) - .parse_mode(MarkdownV2) +pub async fn karma(bot: &Bot, msg: &Message, reply: &Message, text: &String) -> ResponseResult<()> { + let triggers = vec![ + KarmaTrigger::new("спс", 1), + KarmaTrigger::new("спасибо", 1), + KarmaTrigger::new("+", 1), + KarmaTrigger::new("благодарю", 1), + KarmaTrigger::new("пасиб", 1), + KarmaTrigger::new("-", -1), + KarmaTrigger::new("👍", 1), + KarmaTrigger::new("👎", -1), + ]; + for trigger in triggers { + match text.to_lowercase().find(&trigger.text) { + Some(_id) => { + let giver = msg.from().unwrap(); + let reciever = reply.from().unwrap(); + let change_text = match trigger.value { + 1 => "повысил", + -1 => "понизил", + _ => "изменил", + }; + let text = format!( + "*{}* {} карму *{}*", + escape(&giver.first_name), + change_text, + escape(&reciever.first_name) + ); + bot.send_message(msg.chat.id, text) + .parse_mode(MarkdownV2) + .await?; + return Ok(()); + } + None => (), + } + } + Ok(()) +} + +pub async fn offtop(bot: &Bot, msg: &Message) -> ResponseResult<()> { + bot.send_message(msg.chat.id, "Вот вам ссылка на оффтоп") + .reply_to_message_id(msg.id) + .reply_markup(utils::make_offtop_keyboard()) .await?; Ok(()) } diff --git a/src/godette/utils.rs b/src/godette/utils.rs index 4d80956..7afe156 100644 --- a/src/godette/utils.rs +++ b/src/godette/utils.rs @@ -1,7 +1,14 @@ -use teloxide::types::Message; +use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup, Message}; +use url::Url; pub fn get_text_or_empty(msg: &Message) -> String { msg.text() .unwrap_or(msg.caption().unwrap_or("")) .to_string() } + +pub fn make_offtop_keyboard() -> InlineKeyboardMarkup { + let link = Url::parse("https://t.me/Godot_Engine_Offtop").unwrap(); + let button = InlineKeyboardButton::url("Godot Engine оффтоп чат".to_owned(), link); + return InlineKeyboardMarkup::new(vec![[button]]); +} diff --git a/src/main.rs b/src/main.rs index abf0b9e..7eb8e7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,35 +5,15 @@ use teloxide::prelude::*; use godette::commands; use godette::Godette; +use dotenv::dotenv; + #[tokio::main] async fn main() { + dotenv().ok(); pretty_env_logger::init(); let bot = Godette::new(); - let handler = Update::filter_message() - // User commands - .branch( - dptree::entry() - .filter_command::() - .endpoint(Godette::commands_dispatcher), - ) - // Admin commands - .branch( - dptree::entry() - .filter_command::() - .endpoint(Godette::admin_dispatcher), - ) - // Replies - // .branch(Message::filter_reply_to_message().endpoint(Godette::reply_dispatcher)) - // Messages - .branch( - dptree::filter(|msg: Message| { - msg.from() - .map(|user| user.id == UserId(60441930)) - .unwrap_or_default() - }) - .endpoint(Godette::message_dispatcher), - ); + let handler = bot.create_handler(); Dispatcher::builder(bot.bot, handler) .default_handler(|upd| async move { log::warn!("Unhandled update: {:?}", upd);