DONE: unmute command

This commit is contained in:
doryan 2024-06-02 02:30:52 +04:00
parent 7ec67cb6e4
commit 8f43d91f5c
28 changed files with 305 additions and 142 deletions

View File

@ -7,21 +7,23 @@ use telers::{
use tokio::time::{sleep, Duration as DurationSleep};
use crate::{
types::structs::{bot_entity::BotEntity, message_sender::MessageSender},
utils::telegram::try_do_action::try_restrict,
types::structs::{
handler_entity::HandlerEntity,
message_sender::{MessageSender, MessageSenderBuilder},
},
utils::telegram::try_do::try_restrict,
};
use crate::utils::telegram::ban_member::ban_chat_member;
pub async fn ban(bot_entity: BotEntity, delay: u64) -> HandlerResult {
let (bot, message, sender): (Bot, Message, MessageSender) = (
bot_entity.bot_instance,
bot_entity.receive_message,
bot_entity.message_sender,
pub async fn ban(handler_entity: HandlerEntity, chat_id: i64, delay: u64) -> HandlerResult {
let (bot, message, sender): (Bot, Message, MessageSenderBuilder) = (
handler_entity.bot_instance,
handler_entity.message_reciever,
handler_entity.message_sender_builder,
);
let reply_to: Message;
let chat_id: i64 = message.chat().id();
if let Some(msg) = message.reply_to_message() {
reply_to = msg.clone();
@ -29,21 +31,22 @@ pub async fn ban(bot_entity: BotEntity, delay: u64) -> HandlerResult {
sender
.reply_to(message.id())
.text("Ответьте на сообщение, чтобы забанить.")
.build()
.send(&bot)
.await?;
return Ok(EventReturn::Cancel);
}
let user_data: &User = reply_to.from().unwrap();
let user_id: i64 = user_data.id;
let user: &User = reply_to.from().unwrap();
sleep(DurationSleep::from_millis(delay)).await;
let future = || async { ban_chat_member(&bot, user_id, chat_id).await };
let demote_args: (&Bot, i64, i64) = (&bot, user_id, chat_id);
let future = || async { ban_chat_member(&bot, user.id, chat_id).await };
let demote_args: (&Bot, i64, i64) = (&bot, user.id, chat_id);
let failure_sender: MessageSender = sender
.clone()
.text("Невозможно забанить участника чата, демотните и попробуйте снова");
.text("Невозможно забанить участника чата, демотните и попробуйте снова")
.build();
if try_restrict(future, demote_args, failure_sender)
.await
@ -56,6 +59,7 @@ pub async fn ban(bot_entity: BotEntity, delay: u64) -> HandlerResult {
sender
.reply_to(message.id())
.text(format!("Пользователь {} забанен.", banned_user_name))
.build()
.send(&bot)
.await?;

View File

@ -1,2 +1,3 @@
pub mod ban;
pub mod mute;
pub mod unmute;

View File

@ -1,64 +1,74 @@
use futures::stream::futures_unordered;
use telers::{
event::{telegram::HandlerResult, EventReturn},
types::{Message, User},
Bot,
};
use tokio::time::{sleep, Duration as DurationSleep};
use tokio::time::{sleep, Duration};
use crate::{
types::{
enums::time_metrics::TimeMetrics,
structs::{
bot_entity::BotEntity, countable_time::CountableTime, message_sender::MessageSender,
countable_time::CountableTime, handler_entity::HandlerEntity,
message_sender::MessageSenderBuilder,
},
traits::countable_interface::ICountable,
},
utils::telegram::try_do_action::try_restrict,
utils::{
general::unrestrict_date::unrestrict_date,
telegram::{restrict::restrict, try_do::try_restrict},
},
};
use crate::utils::{general::unrestrict_date::unrestrict_date, telegram::restrict::restrict};
type HandlerEntityExtract = (Bot, Message, MessageSenderBuilder);
type TimeValues = (TimeMetrics, u64);
pub async fn mute(bot_entity: BotEntity, values: (TimeMetrics, u64)) -> HandlerResult {
let (bot, message, sender): (Bot, Message, MessageSender) = (
bot_entity.bot_instance,
bot_entity.receive_message,
bot_entity.message_sender,
pub async fn mute(
handler_entity: HandlerEntity,
chat_id: i64,
values: TimeValues,
) -> HandlerResult {
let (bot, message, sender_builder): HandlerEntityExtract = (
handler_entity.bot_instance,
handler_entity.message_reciever,
handler_entity.message_sender_builder,
);
let (metric, delay): TimeValues = values;
let reply_to: Message;
let chat_id: i64 = message.chat().id();
if let Some(msg) = message.reply_to_message() {
reply_to = msg.clone();
} else {
sender
sender_builder
.reply_to(message.id())
.text("Ответьте на сообщение, чтобы замьютить.")
.text("Ответьте на сообщение, чтобы забанить.")
.build()
.send(&bot)
.await?;
return Ok(EventReturn::Cancel);
}
let user_data: &User = reply_to.from().unwrap();
let user_id: i64 = user_data.id;
sleep(Duration::from_millis(delay)).await;
sleep(DurationSleep::from_millis(values.1)).await;
let user: &User = reply_to.from().unwrap();
let time_duration = metric.extract();
let time_duration = values.0.extract();
let unmute_date = unrestrict_date(time_duration);
let postfix = CountableTime::from_value(time_duration)
.get_postfix(values.0)
.get_postfix(metric)
.unwrap();
let unmute_date = unrestrict_date(time_duration);
let future = || async { restrict(&bot, user_id, unmute_date, chat_id).await };
let demote_args: (&Bot, i64, i64) = (&bot, user_id, chat_id);
let failure_sender: MessageSender = sender
let future = || async { restrict(&bot, user.id, unmute_date, chat_id).await };
let demote_args: (&Bot, i64, i64) = (&bot, user.id, chat_id);
let failure = sender_builder
.clone()
.text("Невозможно замьютить участника чата, демотните и попробуйте снова");
if try_restrict(future, demote_args, failure_sender)
if try_restrict(future, demote_args, failure.build())
.await
.is_err()
{
@ -66,12 +76,13 @@ pub async fn mute(bot_entity: BotEntity, values: (TimeMetrics, u64)) -> HandlerR
} else {
let muted_user_name = reply_to.from().unwrap().clone().username.unwrap();
sender
sender_builder
.reply_to(message.id())
.text(format!(
"Пользователь {} замьючен на {:?} {}.",
muted_user_name, time_duration, postfix
))
.build()
.send(&bot)
.await?;

View File

@ -0,0 +1,59 @@
use telers::{
event::{telegram::HandlerResult, EventReturn},
methods::RestrictChatMember,
types::{ChatPermissions, Message},
Bot,
};
use crate::types::{
enums::target_user::TargetUser,
structs::{handler_entity::HandlerEntity, message_sender::MessageSenderBuilder},
};
pub async fn unmute(
handler_entity: HandlerEntity,
chat_id: i64,
user: TargetUser,
) -> HandlerResult {
let (bot, message, sender_builder): (Bot, Message, MessageSenderBuilder) = (
handler_entity.bot_instance,
handler_entity.message_reciever,
handler_entity.message_sender_builder,
);
let user_id: i64 = match user {
TargetUser::Id(id) => id,
TargetUser::Reply => message.reply_to_message().unwrap().from().unwrap().id,
_ => {
return Ok(EventReturn::Cancel);
}
};
let default_member_permissions = ChatPermissions::all()
.can_change_info(false)
.can_manage_topics(false)
.can_invite_users(false)
.can_pin_messages(false);
let bot_action = RestrictChatMember::new(chat_id, user_id, default_member_permissions);
if let Err(error) = bot.send(bot_action).await {
sender_builder
.text(format!(
"Невозможно снять мьют с участника чата по причине: {error:?}"
))
.build()
.send(&bot)
.await?;
Ok(EventReturn::Cancel)
} else {
sender_builder
.reply_to(message.id())
.text("С пользователя был снят мьут.")
.build()
.send(&bot)
.await
.unwrap();
Ok(EventReturn::Finish)
}
}

View File

@ -1,2 +0,0 @@
pub mod help;
pub mod unmute;

View File

@ -1,60 +0,0 @@
use telers::{
event::{telegram::HandlerResult, EventReturn},
filters::CommandObject,
methods::RestrictChatMember,
types::User,
types::{ChatPermissions, Message},
Bot,
};
use crate::types::structs::message_sender::MessageSender;
pub async fn unmute(bot: Bot, message: Message, command: CommandObject) -> HandlerResult {
let sender = MessageSender::new(message.chat().id());
let reply_to: Message;
let chat_id: i64 = message.chat().id();
if let Some(msg) = message.reply_to_message() {
reply_to = msg.clone();
} else {
sender
.reply_to(message.id())
.text("Ответьте на сообщение, чтобы замьютить.")
.send(&bot)
.await?;
return Ok(EventReturn::Cancel);
}
let user_data: &User = reply_to.from().unwrap();
let user_id: i64 = user_data.id;
let default_member_permissions = ChatPermissions::all()
.can_change_info(false)
.can_manage_topics(false)
.can_invite_users(false)
.can_pin_messages(false);
let bot_action = RestrictChatMember::new(chat_id, user_id, default_member_permissions);
let username = reply_to.from().unwrap().clone().username.unwrap();
if let Err(error) = bot.send(bot_action).await {
sender
.text(format!(
"Невозможно снять мьют с участника чата по причине: {error:?}"
))
.send(&bot)
.await?;
return Ok(EventReturn::Cancel);
} else {
sender
.reply_to(message.id())
.text(format!("С пользователя {} был снят мьут.", username))
.send(&bot)
.await
.unwrap();
}
Ok(EventReturn::Finish)
}

View File

@ -8,17 +8,17 @@ use crate::types::structs::message_sender::MessageSender;
const HELP_TEXT: &str = "\
/help - помощь по боту.\n\
/unmute - снимает с человека мьют, нужно ответить на сообщение, чтобы команда сработала (\
только для админов).\n\
/unmute - снимает с человека мьют, для подробностей, введите команду с аргументом -h (тол\
ько для админов).\n\
🎲 - выдаёт мут, для этого нужно отправить ТОЛЬКО эмодзи в ответ на сообщение участника. \
чата, которого вы хотите замьютить (только для админов).\n\
🎰 - выдаёт бан в случае джекпота, напротив, мьют, всё так же кидайте этот эмодзи в ответ \
на сообщение участника чата, которого вы хотите замьютить/забанить (только для админов).";
pub async fn help(bot: Bot, message: Message) -> HandlerResult {
println!("hi");
MessageSender::new(message.chat().id())
MessageSender::builder(message.chat().id())
.text(HELP_TEXT)
.build()
.send(&bot)
.await
.unwrap();

View File

@ -1 +1,2 @@
pub mod endpoints;
pub mod help_command;
pub mod unmute_command;

View File

@ -0,0 +1,89 @@
use telers::{
enums::ParseMode,
event::{telegram::HandlerResult, EventReturn},
filters::CommandObject,
types::Message,
utils::text::{html_formatter::Formatter as HTMLFormatter, Builder as TextBuilder},
Bot,
};
use crate::{
handlers::actions::unmute::unmute,
types::{
enums::target_user::TargetUser,
structs::{
handler_entity::HandlerEntity,
message_sender::{MessageSender, MessageSenderBuilder},
},
},
};
async fn unmute_help(sender: MessageSenderBuilder, bot: &Bot) {
let help_response_builder: TextBuilder<HTMLFormatter> =
TextBuilder::new(HTMLFormatter::default())
.monowidth("/unmute [ID | REPLY]")
.text(
"
\n\nВведите либо ID юзера, либо ответьте на \
сообщение участника чата, с которого вы хотите \
снять мьют.
",
);
let help_response: &str = help_response_builder.get_text();
sender
.text(help_response)
.parse_mode(ParseMode::HTML)
.build()
.send(bot)
.await
.unwrap();
}
pub async fn unmute_command(bot: Bot, message: Message, command: CommandObject) -> HandlerResult {
let args: Vec<&str> = command.args.iter().map(|boxed| &**boxed).collect();
let (message_id, chat_id): (i64, i64) = (message.id(), message.chat().id());
let sender: MessageSenderBuilder = MessageSender::builder(chat_id).reply_to(message_id);
let mut handler_entity: HandlerEntity = HandlerEntity {
bot_instance: bot,
message_reciever: message,
message_sender_builder: sender,
};
match args.first().cloned() {
None => {
if handler_entity.message_reciever.reply_to_message().is_none() {
unmute_help(
handler_entity.message_sender_builder,
&handler_entity.bot_instance,
)
.await;
} else {
let on_reply = TargetUser::Reply;
unmute(handler_entity, chat_id, on_reply).await?;
}
}
Some(id) => {
handler_entity
.message_sender_builder
.set_text("Укажите id пользователя, с которого вы хотите снять мьют");
if let Ok(parsed_id) = id.parse::<i64>() {
let on_id: TargetUser = TargetUser::Id(parsed_id);
unmute(handler_entity, chat_id, on_id).await?;
} else {
handler_entity
.message_sender_builder
.build()
.send(&handler_entity.bot_instance)
.await
.unwrap();
}
}
}
Ok(EventReturn::Finish)
}

View File

@ -8,7 +8,7 @@ use crate::{
handlers::actions::{ban::ban, mute::mute},
types::{
enums::time_metrics::TimeMetrics,
structs::{bot_entity::BotEntity, message_sender::MessageSender},
structs::{handler_entity::HandlerEntity, message_sender::MessageSender},
},
};
@ -18,30 +18,31 @@ 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());
let bot_entity: BotEntity = BotEntity {
let handler_entity: HandlerEntity = HandlerEntity {
bot_instance: bot,
receive_message: message,
message_sender: MessageSender::new(chat_id),
message_reciever: message,
message_sender_builder: MessageSender::builder(chat_id),
};
let (mute_time, emoji): (TimeMetrics, &str) = (TimeMetrics::Days(dice.value), &dice.emoji);
match emoji {
"🎲" => {
mute(bot_entity, (mute_time, DICE_DELAY_MS)).await?;
mute(handler_entity, chat_id, (mute_time, DICE_DELAY_MS)).await?;
}
"🎰" => {
if dice.value == 64 {
ban(bot_entity, CASINO_DELAY_MS).await?;
ban(handler_entity, chat_id, CASINO_DELAY_MS).await?;
} else {
mute(bot_entity, (mute_time, CASINO_DELAY_MS)).await?;
mute(handler_entity, chat_id, (mute_time, CASINO_DELAY_MS)).await?;
}
}
_ => {
bot_entity
.message_sender
handler_entity
.message_sender_builder
.text("Такой эмодзи не имеет привязки к какому либо действию бота.")
.send(&bot_entity.bot_instance)
.build()
.send(&handler_entity.bot_instance)
.await?;
}
}

View File

@ -16,7 +16,7 @@ use middlewares::admin_check_middleware::AdminCheck;
mod handlers;
use handlers::{
commands_handler::endpoints::{help::help, unmute::unmute},
commands_handler::{help_command::help, unmute_command::unmute_command},
dice_handler::dice::dice_handler,
};
@ -50,7 +50,7 @@ async fn main() {
admin_commands
.message
.register(unmute)
.register(unmute_command)
.filter(Command::one("unmute"));
admin_commands

View File

@ -34,8 +34,9 @@ impl InnerMiddleware for AdminCheck {
let response = next(request).await?;
return Ok(response);
} else {
MessageSender::new(chat_id)
MessageSender::builder(chat_id)
.text("У вам нет прав администратора, чтобы использовать эту команду.")
.build()
.send(&bot)
.await
.unwrap();

View File

@ -1 +1,2 @@
pub mod target_user;
pub mod time_metrics;

View File

@ -0,0 +1,7 @@
#[derive(Clone, Default, Debug)]
pub enum TargetUser {
Id(i64),
Reply,
#[default]
None,
}

View File

@ -1,3 +1,5 @@
pub mod enums;
pub mod structs;
pub mod traits;
pub type DynError = Box<dyn std::error::Error>;

View File

@ -1,8 +0,0 @@
use crate::types::structs::message_sender::MessageSender;
use telers::{types::Message, Bot};
pub struct BotEntity {
pub bot_instance: Bot,
pub receive_message: Message,
pub message_sender: MessageSender,
}

View File

@ -3,18 +3,22 @@ use crate::types::{enums::time_metrics::TimeMetrics, traits::countable_interface
pub struct CountableTime(i64, i64);
impl ICountable<(i64, i64), TimeMetrics> for CountableTime {
#[inline]
fn new() -> Self {
Self(0, 0)
}
#[inline]
fn from_value(value: i64) -> Self {
Self((value / 10) % 10, value % 10)
}
#[inline]
fn get_values(&self) -> (i64, i64) {
(self.0, self.1)
}
#[inline]
fn set_values(&self, value: i64) -> Self {
Self((value / 10) % 10, value % 10)
}

View File

@ -0,0 +1,8 @@
use crate::types::structs::message_sender::MessageSenderBuilder;
use telers::{types::Message, Bot};
pub struct HandlerEntity {
pub bot_instance: Bot,
pub message_reciever: Message,
pub message_sender_builder: MessageSenderBuilder,
}

View File

@ -1,43 +1,80 @@
use core::convert::Into;
use telers::{
enums::ParseMode,
errors::session::ErrorKind,
methods::SendMessage,
types::{Message, ReplyParameters},
Bot,
};
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct MessageSender {
chat_id: i64,
send_message: SendMessage,
message: SendMessage,
}
impl MessageSender {
pub fn new(group_id: i64) -> Self {
Self {
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<Message, ErrorKind> {
bot.send(self.message).await
}
}
#[derive(Clone, Debug)]
pub struct MessageSenderBuilder {
chat_id: i64,
send_message: SendMessage,
}
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.clone().chat_id(val);
self.send_message = self.send_message.chat_id(val);
self
}
pub fn text(mut self, val: impl Into<String>) -> Self {
self.send_message = self.send_message.clone().text(val);
self.send_message = self.send_message.text(val);
self
}
pub fn disable_notification(mut self, val: bool) -> Self {
self.send_message = self.send_message.clone().disable_notification(val);
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.clone().reply_parameters(reply);
self.send_message = self.send_message.reply_parameters(reply);
self
}
pub async fn send(self, bot: &Bot) -> Result<Message, ErrorKind> {
bot.send(self.send_message).await
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<String>) {
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,
}
}
}

View File

@ -1,3 +1,3 @@
pub mod bot_entity;
pub mod countable_time;
pub mod handler_entity;
pub mod message_sender;

View File

@ -1,4 +1,4 @@
#[allow(dead_code)]
#[must_use]
pub trait ICountable<T, M> {
fn new() -> Self;

View File

@ -1,5 +1,6 @@
use chrono::{Duration, Local, NaiveDateTime};
#[inline]
pub fn unrestrict_date(days: i64) -> NaiveDateTime {
Local::now().naive_utc() + Duration::days(days)
}

View File

@ -1,5 +1,6 @@
use telers::{errors::session::ErrorKind, methods::BanChatMember, Bot};
#[inline]
pub async fn ban_chat_member(bot: &Bot, chat_id: i64, user_id: i64) -> Result<bool, ErrorKind> {
bot.send(BanChatMember::new(chat_id, user_id)).await
}

View File

@ -1,5 +1,6 @@
use telers::{errors::session::ErrorKind, methods::promote_chat_member::PromoteChatMember, Bot};
#[inline]
pub async fn demote_user(bot: &Bot, user_id: i64, chat_id: i64) -> Result<bool, ErrorKind> {
bot.send(
PromoteChatMember::new(chat_id, user_id)

View File

@ -1,5 +1,6 @@
use telers::{errors::SessionErrorKind, methods::get_chat_administrators, types::ChatMember, Bot};
#[inline]
pub async fn get_all_admins(bot: &Bot, chat_id: i64) -> Result<Vec<ChatMember>, SessionErrorKind> {
bot.send(get_chat_administrators::GetChatAdministrators::new(chat_id))
.await

View File

@ -3,4 +3,4 @@ pub mod ban_member;
pub mod demote;
pub mod get_all_admins;
pub mod restrict;
pub mod try_do_action;
pub mod try_do;

View File

@ -1,6 +1,7 @@
use chrono::NaiveDateTime;
use telers::{errors::session::ErrorKind, methods::*, types::ChatPermissions, Bot};
#[inline]
pub async fn restrict(
bot: &Bot,
user_id: i64,

View File

@ -1,6 +1,6 @@
use telers::{errors::SessionErrorKind as ErrorKind, event::EventReturn, Bot};
use crate::types::structs::message_sender::MessageSender;
use crate::types::{enums::target_user::TargetUser, structs::message_sender::MessageSender};
use std::future::Future;
use super::demote::demote_user;
@ -8,7 +8,8 @@ use super::demote::demote_user;
const DEMOTE_FAILURE_MESSAGE: &str = "\
Нельзя выдать ограничение пользователю, т.к. невозможно демотнуть \
участника посредством бота, если ему выдан админ при помощи других \
админов или владельца чата.";
админов или владельца чата.\
";
pub async fn try_restrict<F, R>(
future_callback: F,
@ -23,8 +24,9 @@ where
if future_callback().await.is_err() {
if demote_user(bot, user_id, chat_id).await.is_err() {
MessageSender::new(chat_id)
MessageSender::builder(chat_id)
.text(DEMOTE_FAILURE_MESSAGE)
.build()
.send(bot)
.await
.unwrap();