diff --git a/src/bots/approved_bot/mod.rs b/src/bots/approved_bot/mod.rs index bead445..c8ec21b 100644 --- a/src/bots/approved_bot/mod.rs +++ b/src/bots/approved_bot/mod.rs @@ -10,13 +10,13 @@ use self::{ modules::{ annotations::get_annotations_handler, book::get_book_handler, download::get_download_hander, help::get_help_handler, random::get_random_hander, - search::get_search_hanlder, settings::get_settings_handler, support::get_support_handler, + search::get_search_handler, settings::get_settings_handler, support::get_support_handler, update_history::get_update_log_handler, }, services::user_settings::{get_user_or_default_lang_codes, update_user_activity}, }; -use super::{ignore_channel_messages, BotCommands, BotHandler}; +use super::{ignore_channel_messages, BotCommands, BotHandler, bots_manager::get_manager_handler}; async fn _update_activity(me: teloxide::types::Me, user: teloxide::types::User) -> Option<()> { tokio::spawn(async move { @@ -78,7 +78,8 @@ pub fn get_approved_handler() -> (BotHandler, BotCommands) { .branch(get_annotations_handler()) .branch(get_book_handler()) .branch(get_update_log_handler()) - .branch(get_search_hanlder()), + .branch(get_manager_handler()) + .branch(get_search_handler()), Some(vec![ BotCommand { command: String::from("random"), diff --git a/src/bots/approved_bot/modules/search.rs b/src/bots/approved_bot/modules/search.rs index 7ce20c2..4f2b679 100644 --- a/src/bots/approved_bot/modules/search.rs +++ b/src/bots/approved_bot/modules/search.rs @@ -261,7 +261,7 @@ pub async fn message_handler(message: Message, bot: AutoSend) -> BotHandler } } -pub fn get_search_hanlder() -> crate::bots::BotHandler { +pub fn get_search_handler() -> crate::bots::BotHandler { dptree::entry().branch( Update::filter_message() .endpoint(|message, bot| async move { message_handler(message, bot).await }), diff --git a/src/bots/bots_manager/mod.rs b/src/bots/bots_manager/mod.rs new file mode 100644 index 0000000..3d56757 --- /dev/null +++ b/src/bots/bots_manager/mod.rs @@ -0,0 +1,59 @@ +use teloxide::prelude::*; + +use std::error::Error; + +use self::{strings::format_registered_message, utils::get_token}; +use crate::config; + +pub mod register; +pub mod strings; +pub mod utils; + +pub async fn message_handler( + message: Message, + bot: AutoSend, +) -> Result<(), Box> { + let from_user = message.from().unwrap(); + let text = message.text().unwrap_or(""); + + let result = register::register(from_user.id, text).await; + + let message_text = match result { + register::RegisterStatus::Success { ref username } => format_registered_message(&username), + register::RegisterStatus::NoToken => strings::HELP_MESSAGE.to_string(), + register::RegisterStatus::WrongToken => strings::ERROR_MESSAGE.to_string(), + register::RegisterStatus::RegisterFail => strings::ALREADY_REGISTERED.to_string(), + }; + + #[allow(unused_must_use)] + { + bot.send_message(message.chat.id, message_text) + .reply_to_message_id(message.id) + .await; + } + + if let register::RegisterStatus::Success { .. } = result { + #[allow(unused_must_use)] + { + bot.send_message( + config::CONFIG.admin_id.clone(), + strings::BOT_REGISTERED_TO_ADMIN, + ) + .await; + } + } + + return Ok(()); +} + +pub fn get_manager_handler() -> Handler< + 'static, + dptree::di::DependencyMap, + Result<(), Box>, + teloxide::dispatching::DpHandlerDescription, +> { + Update::filter_message().branch( + Message::filter_text() + .chain(dptree::filter(|message: Message| { get_token(message.text().unwrap()).is_some() })).endpoint(message_handler), + ) +} diff --git a/src/bots/bots_manager/register.rs b/src/bots/bots_manager/register.rs new file mode 100644 index 0000000..0f760c0 --- /dev/null +++ b/src/bots/bots_manager/register.rs @@ -0,0 +1,76 @@ +use std::collections::HashMap; + +use teloxide::prelude::*; + +use crate::config; + + +#[derive(Debug)] +pub enum RegisterStatus { + Success {username: String}, + NoToken, + WrongToken, + RegisterFail, +} + + +async fn get_bot_username(token: &str) -> Option { + match Bot::new(token).get_me().send().await { + Ok(v) => v.username.clone(), + Err(_) => None + } +} + +async fn make_register_request(user_id: UserId, username: &str, token: &str) -> Result<(), ()> { + let user_id = &user_id.to_string(); + + let data = HashMap::from([ + ("token", token), + ("user", user_id), + ("username", username), + ("status", "pending"), + ("cache", "no_cache") + ]); + + let client = reqwest::Client::new(); + let response = client + .post(config::CONFIG.manager_url.clone()) + .header("Authorization", config::CONFIG.manager_api_key.clone()) + .json(&data) + .send() + .await; + + let status_code = match response { + Ok(v) => v.status(), + Err(_) => return Err(()), + }; + + log::debug!("make_register_request status_code={}", status_code); + + if status_code != 200 { + return Err(()); + } + + Ok(()) +} + + +pub async fn register(user_id: UserId, message_text: &str) -> RegisterStatus { + let token = match super::utils::get_token(message_text) { + Some(v) => v, + None => return RegisterStatus::NoToken + }; + + let bot_username = match get_bot_username(token).await { + Some(v) => v, + None => return RegisterStatus::WrongToken + }; + + let register_request_status = make_register_request(user_id, &bot_username, token).await; + + if register_request_status.is_err() { + return RegisterStatus::RegisterFail; + } + + return RegisterStatus::Success { username: bot_username }; +} diff --git a/src/bots/bots_manager/strings.rs b/src/bots/bots_manager/strings.rs new file mode 100644 index 0000000..b537301 --- /dev/null +++ b/src/bots/bots_manager/strings.rs @@ -0,0 +1,15 @@ +pub const HELP_MESSAGE: &str = " +Зарегистрируй бота в @BotFather . +И перешли сюда сообщение об успешной регистрации. +(Начинается с: Done! Congratulations on your new bot.) +"; + +pub fn format_registered_message(username: &str) -> String { + return format!("@{username} зарегистрирован и через несколько минут будет подключен!", username = username); +} + +pub const ALREADY_REGISTERED: &str= "Ошибка! Возможно бот уже зарегистрирован!"; + +pub const ERROR_MESSAGE: &str = "Ошибка! Что-то не так с ботом!"; + +pub const BOT_REGISTERED_TO_ADMIN: &str = "Новый бот зарегистрирован!"; diff --git a/src/bots/bots_manager/utils.rs b/src/bots/bots_manager/utils.rs new file mode 100644 index 0000000..1f7df37 --- /dev/null +++ b/src/bots/bots_manager/utils.rs @@ -0,0 +1,56 @@ +use regex::Regex; + + +pub fn get_token(message_text: &str) -> Option<&str> { + let re = Regex::new("(?P[0-9]+:[0-9a-zA-Z-_]+)").unwrap(); + + match re.find(message_text) { + Some(v) => Some(v.as_str()), + None => None + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn check_token_fail() { + let message = "wrong_token"; + + let result = get_token(message); + + assert!(result.is_none()) + } + + #[test] + fn check_token_short() { + let message = " + Done! Congratulations on your new bot. You will find it at t.me/aaaa_bot. + You can now add a description, about section and profile picture for your bot, + see /help for a list of commands. + By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. + Just make sure the bot is fully operational before you do this. \ + \ + Use this token to access the HTTP API: \ + 5555555555:AAF-AAAAAAAA1239AA2AAsvy13Axp23RAa \ + Keep your token secure and store it safely, it can be used by anyone to control your bot. \ + \ + For a description of the Bot API, see this page: https://core.telegram.org/bots/api \ + "; + + let result = get_token(message); + + assert_eq!(result.unwrap(), "5555555555:AAF-AAAAAAAA1239AA2AAsvy13Axp23RAa"); + } + + #[test] + fn check_token_long() { + let message = "5555555555:AAF-AAAAAAAA1239AA2AAsvy13Axp23RAa"; + + let result = get_token(message); + + assert_eq!(result.unwrap(), message); + } +} \ No newline at end of file diff --git a/src/bots/mod.rs b/src/bots/mod.rs index 802ff14..84dbaa8 100644 --- a/src/bots/mod.rs +++ b/src/bots/mod.rs @@ -1,4 +1,5 @@ mod approved_bot; +pub mod bots_manager; use std::error::Error; diff --git a/src/config.rs b/src/config.rs index 3bbc009..8d6ecc2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,6 +3,8 @@ pub struct Config { pub webhook_base_url: String, + pub admin_id: String, + pub bot_token: String, pub manager_url: String, pub manager_api_key: String, @@ -32,6 +34,8 @@ impl Config { webhook_base_url: get_env("WEBHOOK_BASE_URL"), + admin_id: get_env("ADMIN_ID"), + bot_token: get_env("BOT_TOKEN"), manager_url: get_env("MANAGER_URL"), manager_api_key: get_env("MANAGER_API_KEY"),