From dd306b7000cb54aa582621d9d3389b3cf0e1f645 Mon Sep 17 00:00:00 2001 From: doryan Date: Thu, 10 Apr 2025 00:46:50 +0400 Subject: [PATCH] REFACTOR!: remove a lot of bad code + structures, remake command args parser, and etc. --- Cargo.toml | 2 +- src/handlers/commands/admin_commands.rs | 92 ++++--------------- src/handlers/commands/info_commands.rs | 20 ++-- src/handlers/commands/mod.rs | 7 +- src/handlers/dice/dice_handler.rs | 39 ++++---- src/handlers/dice/mod.rs | 4 +- src/main.rs | 14 ++- src/middlewares/admin_check_middleware.rs | 33 ++++--- src/types/enums/target_user.rs | 36 ++++---- src/types/enums/time_metrics.rs | 20 ++-- src/types/mod.rs | 4 - src/types/structs/countable_time.rs | 6 +- src/types/structs/handler_entity.rs | 29 ------ src/types/structs/message_sender.rs | 81 ---------------- src/types/structs/mod.rs | 2 - src/utils/general/cast_boxed_array.rs | 11 --- src/utils/general/expiration_date.rs | 15 --- src/utils/general/get_expiration_time.rs | 27 ++++-- src/utils/general/mod.rs | 2 - src/utils/macro_rules/create_handler.rs | 3 +- src/utils/telegram/args_parser.rs | 66 +++++++++++++ src/utils/telegram/args_parsers.rs | 28 ------ src/utils/telegram/data_getters.rs | 20 +--- .../{rights_control.rs => member_rights.rs} | 2 +- src/utils/telegram/mod.rs | 6 +- src/utils/telegram/senders.rs | 21 ++--- src/utils/telegram/try_admin_action.rs | 31 +++++++ src/utils/telegram/try_do.rs | 52 ----------- 28 files changed, 250 insertions(+), 423 deletions(-) delete mode 100644 src/types/structs/handler_entity.rs delete mode 100644 src/types/structs/message_sender.rs delete mode 100644 src/utils/general/cast_boxed_array.rs delete mode 100644 src/utils/general/expiration_date.rs create mode 100644 src/utils/telegram/args_parser.rs delete mode 100644 src/utils/telegram/args_parsers.rs rename src/utils/telegram/{rights_control.rs => member_rights.rs} (96%) create mode 100644 src/utils/telegram/try_admin_action.rs delete mode 100644 src/utils/telegram/try_do.rs diff --git a/Cargo.toml b/Cargo.toml index aa18f08..15929a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ lto = "fat" overflow-checks = false [package] -name = "dorya" +name = "gluon" version = "0.2.0" edition = "2021" diff --git a/src/handlers/commands/admin_commands.rs b/src/handlers/commands/admin_commands.rs index ea65e51..da95f13 100644 --- a/src/handlers/commands/admin_commands.rs +++ b/src/handlers/commands/admin_commands.rs @@ -8,91 +8,39 @@ use telers::{ }; use crate::{ - actions::{ban::ban_member, mute::mute_member, unmute::unmute_member}, - assets::files::{BAN_COMMAND_HELP, MUTE_COMMAND_HELP, UNMUTE_COMMAND_HELP}, - types::{ - enums::{target_user::TargetUser, time_metrics::TimeMetrics}, - structs::handler_entity::HandlerEntity, - }, - utils::{ - general::cast_boxed_array::cast_boxed, - telegram::{args_parsers::get_user, data_getters::get_chat_data, senders::send_html}, - }, + assets::files::{BAN_COMMAND_HELP, MUTE_COMMAND_HELP, UNBAN_COMMAND_HELP, UNMUTE_COMMAND_HELP}, + utils::telegram::{args_parser::parse_args, senders::send_html}, }; -pub async fn admin_command_endpoint( +#[allow(unused)] +const USER_ID_NOT_FOUND: &str = "Для выполнение команды нужно знать ID пользователя, или ввести команду и выполнить её, ответив на сообщение пользователя"; +#[allow(unused)] +const COMMAND_EXECUTION_REJECTED: &str = "Выполнение данной команды невозможно, поскольку пользователю были выданы права администратора модераторами или основателем"; + +pub async fn admin_commands_endpoint( bot: Bot, message: Message, - command: CommandObject, + command_object: CommandObject, ) -> HandlerResult { - let command_type: &str = command.command.deref(); + let (command_type, args) = (command_object.command.deref(), command_object.args.deref()); - let args: Vec<&'static str> = cast_boxed(command.args); + let chat_id = message.chat().id(); - let (chat_id, mut handler_entity): (i64, HandlerEntity) = get_chat_data(&bot, &message); - - let mut duration_argument_position = 0usize; - - let target_user: TargetUser = get_user( - handler_entity.clone(), - args.first().copied(), - &mut duration_argument_position, - ); - - if args.is_empty() && !target_user.exist() { + if let Some(_args) = parse_args(args, &message, command_type) { + match command_type { + "ban" | "unban" | "mute" | "unmute" => todo!(), + _ => unreachable!(), + }; + } else { let help_txt = match command_type { "ban" => BAN_COMMAND_HELP, "mute" => MUTE_COMMAND_HELP, + "unban" => UNBAN_COMMAND_HELP, "unmute" => UNMUTE_COMMAND_HELP, - _ => "Такой команды не существует.", + _ => unreachable!(), }; - send_html(bot, message, help_txt).await?; - - return Ok(EventReturn::Cancel); + send_html(&bot, chat_id, help_txt).await?; } - - handler_entity - .message_sender_builder - .set_text("Нет ID или ответа на сообщение пользователя."); - - match command_type { - "ban" => ban_member(handler_entity, chat_id, target_user, 0).await?, - "mute" => match args.get(duration_argument_position).cloned() { - Some(duration_str) => { - let metric = args - .get(duration_argument_position + 1) - .cloned() - .unwrap_or("d"); - - if let Ok(duration) = duration_str.parse::() { - let mute_duration = TimeMetrics::from(metric, duration); - - mute_member(handler_entity, chat_id, target_user, (mute_duration, 0)).await? - } else { - handler_entity - .message_sender_builder - .build() - .send(&handler_entity.bot_instance) - .await?; - - return Ok(EventReturn::Cancel); - } - } - None => { - handler_entity - .message_sender_builder - .text("Не указана длительность мута.") - .build() - .send(&handler_entity.bot_instance) - .await?; - - return Ok(EventReturn::Cancel); - } - }, - "unmute" => unmute_member(handler_entity, chat_id, target_user).await?, - _ => EventReturn::Finish, - }; - Ok(EventReturn::Finish) } diff --git a/src/handlers/commands/info_commands.rs b/src/handlers/commands/info_commands.rs index 4cba626..34f0cd8 100644 --- a/src/handlers/commands/info_commands.rs +++ b/src/handlers/commands/info_commands.rs @@ -1,6 +1,11 @@ use std::ops::Deref; -use telers::{event::telegram::HandlerResult, filters::CommandObject, types::Message, Bot}; +use telers::{ + event::{telegram::HandlerResult, EventReturn}, + filters::CommandObject, + types::Message, + Bot, +}; use crate::{ assets::files::{HELP_COMMAND_TEXT, PRIVACY_COMMAND_TEXT}, @@ -10,12 +15,13 @@ use crate::{ #[inline] pub async fn info_commands_endpoint( bot: Bot, - msg: Message, - command: CommandObject, + message: Message, + command_object: CommandObject, ) -> HandlerResult { - match command.command.deref() { - "help" => send_html(bot, msg, HELP_COMMAND_TEXT).await, - "privacy" => send_html(bot, msg, PRIVACY_COMMAND_TEXT).await, - _ => Ok(telers::event::EventReturn::Cancel), + let chat_id = message.chat().id(); + match command_object.command.deref() { + "help" => send_html(&bot, chat_id, HELP_COMMAND_TEXT).await, + "privacy" => send_html(&bot, chat_id, PRIVACY_COMMAND_TEXT).await, + _ => Ok(EventReturn::Cancel), } } diff --git a/src/handlers/commands/mod.rs b/src/handlers/commands/mod.rs index 3ae4fef..ed1d2cd 100644 --- a/src/handlers/commands/mod.rs +++ b/src/handlers/commands/mod.rs @@ -1,2 +1,5 @@ -pub mod admin_commands; -pub mod info_commands; +mod admin_commands; +mod info_commands; + +pub use admin_commands::*; +pub use info_commands::*; diff --git a/src/handlers/dice/dice_handler.rs b/src/handlers/dice/dice_handler.rs index a26b50b..9c71e47 100644 --- a/src/handlers/dice/dice_handler.rs +++ b/src/handlers/dice/dice_handler.rs @@ -1,48 +1,43 @@ +use std::time::Duration; + use telers::{ event::{telegram::HandlerResult, EventReturn}, types::{Dice, Message}, Bot, }; +use tokio::time::sleep; use crate::{ - actions::{ban::ban_member, mute::mute_member}, - types::{ - enums::{target_user::TargetUser, time_metrics::TimeMetrics}, - structs::{handler_entity::HandlerEntity, message_sender::MessageSender}, - }, + types::enums::{target_user::TargetUser, time_metrics::TimeDuration}, + utils::telegram::args_parser::Argument, }; const DICE_DELAY_MS: u64 = 4000u64; const CASINO_DELAY_MS: u64 = 1500u64; -pub async fn dice_handler(bot: Bot, message: Message) -> HandlerResult { - let (chat_id, dice): (i64, Dice) = (message.chat().id(), message.dice().unwrap().clone()); +pub async fn dice_handler(_bot: Bot, message: Message) -> HandlerResult { + let (_chat_id, dice): (i64, Dice) = (message.chat().id(), message.dice().unwrap().clone()); - let sender = MessageSender::builder(chat_id); - let handler_entity = HandlerEntity::new(bot, message, sender); + let (mute_time, emoji): (TimeDuration, &str) = (TimeDuration::Days(dice.value), &dice.emoji); - let (mute_time, emoji): (TimeMetrics, &str) = (TimeMetrics::Days(dice.value), &dice.emoji); - - let target = TargetUser::Reply(handler_entity.message_reciever.clone()); + let target_user = TargetUser::Reply(message.clone()); + let _args = [Argument::User(target_user), Argument::Time(mute_time)]; match emoji { "🎲" => { - mute_member(handler_entity, chat_id, target, (mute_time, DICE_DELAY_MS)).await?; + sleep(Duration::from_millis(DICE_DELAY_MS)).await; + todo!() } "🎰" => { if dice.value == 64 { - ban_member(handler_entity, chat_id, target, CASINO_DELAY_MS).await?; + sleep(Duration::from_millis(CASINO_DELAY_MS)).await; + todo!() } else { - mute_member( - handler_entity, - chat_id, - target, - (mute_time, CASINO_DELAY_MS), - ) - .await?; + sleep(Duration::from_millis(CASINO_DELAY_MS)).await; + todo!() } } - _ => () + _ => (), } Ok(EventReturn::Finish) diff --git a/src/handlers/dice/mod.rs b/src/handlers/dice/mod.rs index df63795..4fd31eb 100644 --- a/src/handlers/dice/mod.rs +++ b/src/handlers/dice/mod.rs @@ -1 +1,3 @@ -pub mod dice_handler; +mod dice_handler; + +pub use dice_handler::*; diff --git a/src/main.rs b/src/main.rs index 5e3b5a2..f5df45a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use telers::{ Bot, Dispatcher, Router, }; -mod actions; mod assets; mod handlers; mod middlewares; @@ -17,8 +16,8 @@ mod utils; use middlewares::admin_check_middleware::AdminCheck; use handlers::{ - commands::{admin_commands::admin_command_endpoint, info_commands::info_commands_endpoint}, - dice::dice_handler::dice_handler, + commands::{admin_commands_endpoint, info_commands_endpoint}, + dice::dice_handler, }; #[cfg(debug_assertions)] @@ -65,7 +64,14 @@ async fn main() { let mut default_commands = Router::new("default_commands"); create_handler!(default_commands, info_commands_endpoint, help, privacy); - create_handler!(admin_commands, admin_command_endpoint, mute, unmute, ban); + create_handler!( + admin_commands, + admin_commands_endpoint, + ban, + unban, + mute, + unmute + ); admin_commands .message diff --git a/src/middlewares/admin_check_middleware.rs b/src/middlewares/admin_check_middleware.rs index cf0b160..c511917 100644 --- a/src/middlewares/admin_check_middleware.rs +++ b/src/middlewares/admin_check_middleware.rs @@ -2,6 +2,7 @@ use async_trait::async_trait; use telers::{ errors::{EventErrorKind, HandlerError}, event::telegram::HandlerResponse, + methods::SendMessage, middlewares::{InnerMiddleware, Next}, types::Message, Request, @@ -9,10 +10,7 @@ use telers::{ use anyhow::Error as Reject; -use crate::{ - types::structs::message_sender::MessageSender, - utils::telegram::{admin_check::is_admin, data_getters::get_all_admins}, -}; +use crate::utils::telegram::{admin_check::is_admin, data_getters::get_all_admins}; #[derive(Default)] pub struct AdminCheck {} @@ -20,16 +18,23 @@ pub struct AdminCheck {} #[async_trait] impl InnerMiddleware for AdminCheck { async fn call(&self, request: Request, next: Next) -> Result { - let (bot, message) = (request.clone().bot, request.clone().update); + let (bot, message) = (request.bot.clone(), request.update.clone()); let is_replying_dice: Option = match message.kind().message().unwrap() { Message::Dice(dice) => dice.reply_to_message.clone(), _ => None, }; - let admins_list = get_all_admins(&bot, message.chat().unwrap().id()) - .await - .unwrap(); + let chat = match message.chat() { + Some(chat) => chat, + None => { + return Err(EventErrorKind::Handler(HandlerError::from_display( + "Chat not found", + ))) + } + }; + + let admins_list = get_all_admins(&bot, chat.id()).await.unwrap(); let chat_id: i64 = message.chat_id().unwrap(); @@ -38,12 +43,12 @@ impl InnerMiddleware for AdminCheck { return Ok(response); } else { if is_replying_dice.is_some() { - MessageSender::builder(chat_id) - .text("Недостаточно прав для использования данной команды.") - .build() - .send(&bot) - .await - .unwrap(); + bot.send(SendMessage::new( + chat_id, + "Недостаточно прав для использования данной команды.", + )) + .await + .ok(); } return Err(EventErrorKind::Handler(HandlerError::new(Reject::msg( diff --git a/src/types/enums/target_user.rs b/src/types/enums/target_user.rs index 54fa7b7..242b25a 100644 --- a/src/types/enums/target_user.rs +++ b/src/types/enums/target_user.rs @@ -14,6 +14,15 @@ pub enum TargetUser { None, } +impl From> for TargetUser { + fn from(value: Option) -> Self { + match value { + Some(id) => TargetUser::Id(id), + None => TargetUser::None, + } + } +} + impl TargetUser { #[allow(dead_code)] pub fn exist(&self) -> bool { @@ -21,10 +30,9 @@ impl TargetUser { Self::Id(_id) => true, Self::Reply(msg) => { if let Some(replied_msg) = msg.reply_to_message() { - replied_msg.from().map(|user| user.id).is_some() - } else { - false + return replied_msg.from().map(|user| user.id).is_some(); } + false } Self::CurrentMessage(msg) => msg.from().map(|user| user.id).is_some(), Self::None => false, @@ -36,10 +44,9 @@ impl TargetUser { Self::Id(id) => Some(*id), Self::Reply(msg) => { if let Some(replied_msg) = msg.reply_to_message() { - replied_msg.from().map(|user| user.id) - } else { - None + return replied_msg.from().map(|user| user.id); } + None } Self::CurrentMessage(msg) => msg.from().map(|user| user.id), Self::None => None, @@ -53,31 +60,28 @@ impl TargetUser { bot.send(GetChatMember::new(msg.chat().id(), *id)).await; if let Ok(member_kind) = get_chat_member_result { - match member_kind { + return match member_kind { ChatMember::Owner(member) => member.user.username, ChatMember::Administrator(member) => member.user.username, ChatMember::Member(member) => member.user.username, ChatMember::Restricted(member) => member.user.username, ChatMember::Left(member) => member.user.username, ChatMember::Banned(member) => member.user.username, - } - } else { - None + }; } + None } Self::Reply(msg) => { if let Some(replied_msg) = msg.reply_to_message() { - replied_msg.from().unwrap().username.clone() - } else { - None + return replied_msg.from().unwrap().username.clone(); } + None } Self::CurrentMessage(msg) => { if let Some(replied_msg) = msg.from() { - replied_msg.username.clone() - } else { - None + return replied_msg.username.clone(); } + None } Self::None => None, } diff --git a/src/types/enums/time_metrics.rs b/src/types/enums/time_metrics.rs index 3d3641f..342c3bd 100644 --- a/src/types/enums/time_metrics.rs +++ b/src/types/enums/time_metrics.rs @@ -1,6 +1,6 @@ #[allow(dead_code)] -#[derive(Debug, Copy, Clone)] -pub enum TimeMetrics { +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum TimeDuration { Minutes(i64), Hours(i64), Days(i64), @@ -8,23 +8,23 @@ pub enum TimeMetrics { Mounths(i64), } -impl TimeMetrics { - pub fn from(metric: impl Into<&'static str>, duration: i64) -> Self { +impl<'a> TimeDuration { + pub fn from(metric: impl Into<&'a str>, duration: i64) -> Option { match metric.into() { "m" | "min" | "minutes" | "minute" | "минута" | "минуты" | "минут" | "мин" | "м" => { - Self::Minutes(duration) + Some(Self::Minutes(duration)) } - "h" | "hours" | "hour" | "час" | "часов" | "ч" => Self::Hours(duration), + "h" | "hours" | "hour" | "час" | "часов" | "ч" => Some(Self::Hours(duration)), "d" | "days" | "day" | "день" | "дня" | "дней" | "д" => { - Self::Days(duration) + Some(Self::Days(duration)) } "w" | "weeks" | "week" | "недель" | "недели" | "неделя" | "н" => { - Self::Weeks(duration) + Some(Self::Weeks(duration)) } "M" | "months" | "month" | "месяц" | "месяца" | "месяцев" | "мес" | "М" => { - Self::Mounths(duration) + Some(Self::Mounths(duration)) } - _ => Self::Days(duration), + _ => None, } } diff --git a/src/types/mod.rs b/src/types/mod.rs index b8ba81f..dc6734f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,7 +1,3 @@ -use enums::time_metrics::TimeMetrics; - pub mod enums; pub mod structs; pub mod traits; - -pub type TimeValues = (TimeMetrics, u64); diff --git a/src/types/structs/countable_time.rs b/src/types/structs/countable_time.rs index 5a738c6..f5791ad 100644 --- a/src/types/structs/countable_time.rs +++ b/src/types/structs/countable_time.rs @@ -1,8 +1,8 @@ -use crate::types::{enums::time_metrics::TimeMetrics, traits::countable_interface::ICountable}; +use crate::types::{enums::time_metrics::TimeDuration, traits::countable_interface::ICountable}; pub struct CountableTime(i64, i64); -impl ICountable<(i64, i64), TimeMetrics> for CountableTime { +impl ICountable<(i64, i64), TimeDuration> for CountableTime { #[inline] fn new() -> Self { Self(0, 0) @@ -23,7 +23,7 @@ impl ICountable<(i64, i64), TimeMetrics> for CountableTime { Self((value / 10) % 10, value % 10) } - fn get_postfix(&self, metrics: TimeMetrics) -> Option { + fn get_postfix(&self, metrics: TimeDuration) -> Option { let all_word_declensions = metrics.get_word_declensions(); let (first, second, third): (String, String, String) = ( all_word_declensions.0.into(), diff --git a/src/types/structs/handler_entity.rs b/src/types/structs/handler_entity.rs deleted file mode 100644 index 4fee2f4..0000000 --- a/src/types/structs/handler_entity.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::types::structs::message_sender::MessageSenderBuilder; -use telers::{types::Message, Bot}; - -pub type ExtractedEntityData = (Bot, Message, MessageSenderBuilder); - -#[derive(Clone)] -pub struct HandlerEntity { - pub bot_instance: Bot, - pub message_reciever: Message, - pub message_sender_builder: MessageSenderBuilder, -} - -impl HandlerEntity { - pub fn new(bot: Bot, msg: Message, msg_builder: MessageSenderBuilder) -> Self { - Self { - bot_instance: bot, - message_reciever: msg, - message_sender_builder: msg_builder, - } - } - #[inline] - pub fn extract(self) -> ExtractedEntityData { - ( - self.bot_instance, - self.message_reciever, - self.message_sender_builder, - ) - } -} diff --git a/src/types/structs/message_sender.rs b/src/types/structs/message_sender.rs deleted file mode 100644 index 8f75a38..0000000 --- a/src/types/structs/message_sender.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::convert::Into; -use telers::{ - enums::ParseMode, - errors::session::ErrorKind, - methods::SendMessage, - types::{Message, ReplyParameters}, - Bot, -}; - -#[derive(Clone, Debug)] -pub struct MessageSender { - message: SendMessage, -} - -impl MessageSender { - pub fn builder(group_id: i64) -> MessageSenderBuilder { - MessageSenderBuilder { - chat_id: group_id, - send_message: SendMessage::new(group_id, ""), - } - } - pub async fn send(self, bot: &Bot) -> Result { - bot.send(self.message).await - } -} - -#[derive(Clone, Debug)] -pub struct MessageSenderBuilder { - chat_id: i64, - send_message: SendMessage, -} - -#[allow(dead_code)] -impl MessageSenderBuilder { - pub fn parse_mode(mut self, parse_mode: ParseMode) -> Self { - self.send_message = self.send_message.parse_mode(parse_mode); - self - } - pub fn group_id(mut self, val: i64) -> Self { - self.chat_id = val; - self.send_message = self.send_message.chat_id(val); - self - } - pub fn text(mut self, val: impl Into) -> Self { - self.send_message = self.send_message.text(val); - self - } - pub fn disable_notification(mut self, val: bool) -> Self { - self.send_message = self.send_message.disable_notification(val); - self - } - pub fn reply_to(mut self, msg_id: i64) -> Self { - let reply = ReplyParameters::new(msg_id).chat_id(self.chat_id); - self.send_message = self.send_message.reply_parameters(reply); - self - } - - pub fn set_parse_mode(&mut self, parse_mode: ParseMode) { - self.send_message = self.send_message.clone().parse_mode(parse_mode); - } - pub fn set_group_id(&mut self, val: i64) { - self.chat_id = val; - self.send_message = self.send_message.clone().chat_id(val); - } - pub fn set_text(&mut self, val: impl Into) { - self.send_message = self.send_message.clone().text(val); - } - pub fn set_disable_notification(&mut self, val: bool) { - self.send_message = self.send_message.clone().disable_notification(val); - } - pub fn set_reply_to(&mut self, msg_id: i64) { - let reply = ReplyParameters::new(msg_id).chat_id(self.chat_id); - self.send_message = self.send_message.clone().reply_parameters(reply); - } - - pub fn build(self) -> MessageSender { - MessageSender { - message: self.send_message, - } - } -} diff --git a/src/types/structs/mod.rs b/src/types/structs/mod.rs index 72f831c..18eb60f 100644 --- a/src/types/structs/mod.rs +++ b/src/types/structs/mod.rs @@ -1,3 +1 @@ pub mod countable_time; -pub mod handler_entity; -pub mod message_sender; diff --git a/src/utils/general/cast_boxed_array.rs b/src/utils/general/cast_boxed_array.rs deleted file mode 100644 index e681d31..0000000 --- a/src/utils/general/cast_boxed_array.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub fn cast_box<'a>(boxed: Box) -> &'a str { - unsafe { &*Box::into_raw(boxed) } -} - -#[allow(clippy::boxed_local)] -pub fn cast_boxed<'a>(boxed_array: Box<[Box]>) -> Vec<&'a str> { - boxed_array - .iter() - .map(|arg| cast_box(arg.to_owned())) - .collect() -} diff --git a/src/utils/general/expiration_date.rs b/src/utils/general/expiration_date.rs deleted file mode 100644 index 036e741..0000000 --- a/src/utils/general/expiration_date.rs +++ /dev/null @@ -1,15 +0,0 @@ -use chrono::{Duration, Local, NaiveDateTime}; - -use crate::types::{enums::time_metrics::TimeMetrics, TimeValues}; - -#[inline] -pub fn expiration_date(duration: TimeValues) -> NaiveDateTime { - let mute_duration = match duration.0 { - TimeMetrics::Minutes(min) => Duration::minutes(min), - TimeMetrics::Hours(hrs) => Duration::hours(hrs), - TimeMetrics::Days(day) => Duration::days(day), - TimeMetrics::Weeks(wks) => Duration::weeks(wks), - TimeMetrics::Mounths(mon) => Duration::weeks(mon * 4), - }; - Local::now().naive_utc() + mute_duration -} diff --git a/src/utils/general/get_expiration_time.rs b/src/utils/general/get_expiration_time.rs index 4044e45..5946349 100644 --- a/src/utils/general/get_expiration_time.rs +++ b/src/utils/general/get_expiration_time.rs @@ -1,18 +1,29 @@ -use chrono::NaiveDateTime; - use crate::types::{ - structs::countable_time::CountableTime, traits::countable_interface::ICountable, TimeValues, + enums::time_metrics::TimeDuration, structs::countable_time::CountableTime, + traits::countable_interface::ICountable, }; -use super::expiration_date::expiration_date; +use chrono::{Duration, Local, NaiveDateTime}; pub type ExtractedDuration = (NaiveDateTime, String, i64); -pub fn get_expiration_time(time: TimeValues) -> ExtractedDuration { - let time_duration = time.0.extract(); - let unmute_date = expiration_date(time); +#[inline] +pub fn get_expiration_date(duration: TimeDuration) -> NaiveDateTime { + let mute_duration = match duration { + TimeDuration::Minutes(min) => Duration::minutes(min), + TimeDuration::Hours(hrs) => Duration::hours(hrs), + TimeDuration::Days(day) => Duration::days(day), + TimeDuration::Weeks(wks) => Duration::weeks(wks), + TimeDuration::Mounths(mon) => Duration::weeks(mon * 4), + }; + Local::now().naive_utc() + mute_duration +} + +pub fn get_expiration_time(time: TimeDuration) -> ExtractedDuration { + let time_duration = time.extract(); + let unmute_date = get_expiration_date(time); let postfix = CountableTime::from_value(time_duration) - .get_postfix(time.0) + .get_postfix(time) .unwrap(); (unmute_date, postfix, time_duration) diff --git a/src/utils/general/mod.rs b/src/utils/general/mod.rs index efcc1a6..b898df7 100644 --- a/src/utils/general/mod.rs +++ b/src/utils/general/mod.rs @@ -1,3 +1 @@ -pub mod expiration_date; pub mod get_expiration_time; -pub mod cast_boxed_array; diff --git a/src/utils/macro_rules/create_handler.rs b/src/utils/macro_rules/create_handler.rs index 4f5109c..3975d17 100644 --- a/src/utils/macro_rules/create_handler.rs +++ b/src/utils/macro_rules/create_handler.rs @@ -1,11 +1,10 @@ #[macro_export] macro_rules! create_handler { ($branch:expr, $command:expr) => { - $($branch + $branch .message .register($command) .filter(Command::one(stringify!($command))); - )* }; ($branch:expr, $command:expr, $($endpoint:expr), *) => { $branch diff --git a/src/utils/telegram/args_parser.rs b/src/utils/telegram/args_parser.rs new file mode 100644 index 0000000..c8a527d --- /dev/null +++ b/src/utils/telegram/args_parser.rs @@ -0,0 +1,66 @@ +use std::{collections::VecDeque, ops::Deref}; + +use telers::types::Message; + +use crate::types::enums::{target_user::TargetUser, time_metrics::TimeDuration}; + +#[derive(Debug)] +pub enum Argument { + User(TargetUser), + Time(TimeDuration), + Reason(String), +} + +pub fn parse_args( + args: &[Box], + message: &Message, + command_type: &str, +) -> Option> { + if args.is_empty() && message.reply_to_message().is_none() { + return None; + } + + let mut raw_args: VecDeque<&str> = args.iter().map(|arg| arg.deref()).collect(); + let mut parsed_args: Vec = Vec::new(); + + let user_id = match message.reply_to_message() { + Some(reply_message) => TargetUser::from(reply_message.from_id()), + None => match raw_args.pop_front() { + Some(arg) => TargetUser::from(arg.parse::().ok()), + None => TargetUser::default(), + }, + }; + + parsed_args.push(Argument::User(user_id)); + + match command_type { + "mute" | "tban" => 'raw_time_parsing: { + let time = match raw_args.pop_front() { + Some(raw_time) => raw_time.parse::().unwrap_or(0), + None => break 'raw_time_parsing, + }; + + if time == 0 { + break 'raw_time_parsing; + } + + if let Some(raw_time_metric) = raw_args.pop_front() { + let time_metric = match TimeDuration::from(raw_time_metric, time) { + Some(metric) => metric, + None => TimeDuration::Days(time), + }; + + parsed_args.push(Argument::Time(time_metric)); + }; + } + _ => {} + } + + if !raw_args.is_empty() { + let reason = raw_args.iter().fold(String::new(), |acc, v| acc + v + " "); + + parsed_args.push(Argument::Reason(reason.trim_end().to_string())); + } + + Some(parsed_args) +} diff --git a/src/utils/telegram/args_parsers.rs b/src/utils/telegram/args_parsers.rs deleted file mode 100644 index 6b490b6..0000000 --- a/src/utils/telegram/args_parsers.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::types::{ - enums::target_user::TargetUser, - structs::handler_entity::HandlerEntity -}; - -pub fn get_user( - handler_entity: HandlerEntity, - arg: Option<&str>, - arg_pos: &mut usize, -) -> TargetUser { - match ( - handler_entity.message_reciever.reply_to_message(), - arg, - ) { - (Some(msg), _) => TargetUser::CurrentMessage(msg.clone()), - (None, Some(raw_id)) => { - *arg_pos += 1; - if let Ok(id) = raw_id.parse::() { - TargetUser::Id(id) - } else { - TargetUser::None -} - } - (None, None) => { - TargetUser::None - } - } -} diff --git a/src/utils/telegram/data_getters.rs b/src/utils/telegram/data_getters.rs index 5938f38..4cc7e8c 100644 --- a/src/utils/telegram/data_getters.rs +++ b/src/utils/telegram/data_getters.rs @@ -1,22 +1,6 @@ -use telers::{ - methods::GetChatAdministrators, - types::{ChatMember, Message}, - Bot, - errors::SessionErrorKind -}; - -use crate::types::structs::{handler_entity::HandlerEntity, message_sender::MessageSender}; - -pub fn get_chat_data(bot: &Bot, message: &Message) -> (i64, HandlerEntity) { - let (message_id, chat_id): (i64, i64) = (message.id(), message.chat().id()); - let sender = MessageSender::builder(chat_id).reply_to(message_id); - let handler_entity: HandlerEntity = HandlerEntity::new(bot.clone(), message.clone(), sender); - - (chat_id, handler_entity) -} +use telers::{errors::SessionErrorKind, methods::GetChatAdministrators, types::ChatMember, Bot}; #[inline] pub async fn get_all_admins(bot: &Bot, chat_id: i64) -> Result, SessionErrorKind> { - bot.send(GetChatAdministrators::new(chat_id)) - .await + bot.send(GetChatAdministrators::new(chat_id)).await } diff --git a/src/utils/telegram/rights_control.rs b/src/utils/telegram/member_rights.rs similarity index 96% rename from src/utils/telegram/rights_control.rs rename to src/utils/telegram/member_rights.rs index 759fb51..36b1648 100644 --- a/src/utils/telegram/rights_control.rs +++ b/src/utils/telegram/member_rights.rs @@ -9,7 +9,7 @@ pub async fn restrict( chat_id: i64, ) -> Result { bot.send( - restrict_chat_member::RestrictChatMember::new( + RestrictChatMember::new( chat_id, user_id, ChatPermissions::new() diff --git a/src/utils/telegram/mod.rs b/src/utils/telegram/mod.rs index 2b27ebd..928d277 100644 --- a/src/utils/telegram/mod.rs +++ b/src/utils/telegram/mod.rs @@ -1,6 +1,6 @@ pub mod admin_check; -pub mod args_parsers; +pub mod args_parser; pub mod data_getters; -pub mod rights_control; +pub mod member_rights; pub mod senders; -pub mod try_do; +pub mod try_admin_action; diff --git a/src/utils/telegram/senders.rs b/src/utils/telegram/senders.rs index ce2b138..3110ff1 100644 --- a/src/utils/telegram/senders.rs +++ b/src/utils/telegram/senders.rs @@ -1,21 +1,12 @@ use telers::{ - event::{ - telegram::HandlerResult, - EventReturn - }, - enums::ParseMode, - types::Message, - Bot + enums::ParseMode, + event::{telegram::HandlerResult, EventReturn}, + methods::SendMessage, + Bot, }; -use crate::types::structs::message_sender::MessageSender; - -pub async fn send_html(bot: Bot, message: Message, info_text: &str) -> HandlerResult { - MessageSender::builder(message.chat().id()) - .text(info_text) - .parse_mode(ParseMode::HTML) - .build() - .send(&bot) +pub async fn send_html(bot: &Bot, chat_id: i64, text: &str) -> HandlerResult { + bot.send(SendMessage::new(chat_id, text).parse_mode(ParseMode::HTML)) .await?; Ok(EventReturn::Finish) diff --git a/src/utils/telegram/try_admin_action.rs b/src/utils/telegram/try_admin_action.rs new file mode 100644 index 0000000..5b34e8f --- /dev/null +++ b/src/utils/telegram/try_admin_action.rs @@ -0,0 +1,31 @@ +use telers::{ + errors::{HandlerError, SessionErrorKind}, + event::simple::HandlerResult, + methods::SendMessage, + Bot, +}; + +use super::member_rights::demote_user; + +const DEMOTE_ERROR: &str = "Невозможно снять привелегий администратора в силу того, что права были выданы одним из администраторов или основателем"; + +pub async fn try_admin_action( + callback: F, + bot: &Bot, + chat_id: i64, + user_id: i64, +) -> HandlerResult +where + F: Copy + AsyncFnOnce(i64) -> Result, +{ + if callback(user_id).await.is_err() { + if demote_user(bot, user_id, chat_id).await.is_err() { + bot.send(SendMessage::new(chat_id, DEMOTE_ERROR)).await?; + return Err(HandlerError::from_display("DemoteFailure")); + } else { + callback(user_id).await; + } + } + + Ok(()) +} diff --git a/src/utils/telegram/try_do.rs b/src/utils/telegram/try_do.rs deleted file mode 100644 index b8f44a0..0000000 --- a/src/utils/telegram/try_do.rs +++ /dev/null @@ -1,52 +0,0 @@ -use telers::{errors::SessionErrorKind as ErrorKind, event::EventReturn, types::ChatMember, Bot}; - -use crate::types::structs::message_sender::MessageSender; -use std::future::Future; - -use super::{admin_check::is_admin, data_getters::get_all_admins, rights_control::demote_user}; - -const DEMOTE_FAILURE_MESSAGE: &str = "Команда не может быть выполнена: \ - не удалось удалить административные привилегии пользователя."; - -pub async fn try_restrict( - future_callback: F, - demote_args: (&Bot, i64, i64), - failure_sender: MessageSender, -) -> Result<(), EventReturn> -where - R: Future>, - F: Copy + Fn() -> R, -{ - let (bot, user_id, chat_id): (&Bot, i64, i64) = demote_args; - - let admins: Vec = get_all_admins(bot, chat_id).await.unwrap(); - - if is_admin(&admins, user_id) { - MessageSender::builder(chat_id) - .text("Нельзя применить эту команду на пользователе/бота, имеющего привелегии администратора.") - .build() - .send(bot) - .await - .unwrap(); - return Err(EventReturn::Cancel); - } - - if future_callback().await.is_err() { - if demote_user(bot, user_id, chat_id).await.is_err() { - MessageSender::builder(chat_id) - .text(DEMOTE_FAILURE_MESSAGE) - .build() - .send(bot) - .await - .unwrap(); - return Err(EventReturn::Cancel); - } - - if future_callback().await.is_err() { - failure_sender.send(bot).await.unwrap(); - return Err(EventReturn::Cancel); - } - } - - Ok(()) -}