2020-06-24 19:43:21 +02:00
|
|
|
use std::str::FromStr;
|
2020-02-13 19:26:06 +01:00
|
|
|
|
2020-02-13 18:23:22 +01:00
|
|
|
use teloxide::{
|
2020-07-03 19:00:05 +02:00
|
|
|
prelude::*, types::ChatPermissions, utils::command::BotCommand
|
2020-02-13 18:23:22 +01:00
|
|
|
};
|
2020-02-11 20:35:22 +01:00
|
|
|
|
2020-02-18 23:54:41 +01:00
|
|
|
use futures::future;
|
|
|
|
|
2020-02-13 19:11:56 +01:00
|
|
|
// Derive BotCommand to parse text with a command into this enumeration.
|
|
|
|
//
|
|
|
|
// 1. rename = "lowercase" turns all the commands into lowercase letters.
|
|
|
|
// 2. `description = "..."` specifies a text before all the commands.
|
|
|
|
//
|
|
|
|
// That is, you can just call Command::descriptions() to get a description of
|
2020-02-13 19:20:22 +01:00
|
|
|
// your commands in this format:
|
|
|
|
// %GENERAL-DESCRIPTION%
|
|
|
|
// %PREFIX%%COMMAND% - %DESCRIPTION%
|
2020-02-11 20:35:22 +01:00
|
|
|
#[derive(BotCommand)]
|
2020-02-13 18:23:22 +01:00
|
|
|
#[command(
|
|
|
|
rename = "lowercase",
|
2020-06-24 19:43:21 +02:00
|
|
|
description = "Use commands in format /%command% %num% %unit%",
|
|
|
|
parse_with = "split"
|
2020-02-13 18:23:22 +01:00
|
|
|
)]
|
2020-02-11 20:35:22 +01:00
|
|
|
enum Command {
|
|
|
|
#[command(description = "kick user from chat.")]
|
|
|
|
Kick,
|
|
|
|
#[command(description = "ban user in chat.")]
|
2020-06-24 19:43:21 +02:00
|
|
|
Ban {
|
|
|
|
time: u32,
|
|
|
|
unit: UnitOfTime,
|
|
|
|
},
|
2020-02-11 20:35:22 +01:00
|
|
|
#[command(description = "mute user in chat.")]
|
2020-06-24 19:43:21 +02:00
|
|
|
Mute {
|
|
|
|
time: u32,
|
|
|
|
unit: UnitOfTime,
|
|
|
|
},
|
2020-02-11 20:35:22 +01:00
|
|
|
Help,
|
|
|
|
}
|
|
|
|
|
2020-06-24 19:43:21 +02:00
|
|
|
enum UnitOfTime {
|
|
|
|
Seconds,
|
|
|
|
Minutes,
|
|
|
|
Hours,
|
2020-02-11 20:35:22 +01:00
|
|
|
}
|
|
|
|
|
2020-06-24 19:43:21 +02:00
|
|
|
impl FromStr for UnitOfTime {
|
|
|
|
type Err = &'static str;
|
|
|
|
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
|
|
|
|
match s {
|
|
|
|
"h" | "hours" => Ok(UnitOfTime::Hours),
|
|
|
|
"m" | "minutes" => Ok(UnitOfTime::Minutes),
|
|
|
|
"s" | "seconds" => Ok(UnitOfTime::Seconds),
|
|
|
|
_ => Err("Allowed units: h, m, s"),
|
|
|
|
}
|
2020-02-11 20:35:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-24 19:43:21 +02:00
|
|
|
// Calculates time of user restriction.
|
|
|
|
fn calc_restrict_time(time: u32, unit: UnitOfTime) -> u32 {
|
|
|
|
match unit {
|
|
|
|
UnitOfTime::Hours => time * 3600,
|
|
|
|
UnitOfTime::Minutes => time * 60,
|
|
|
|
UnitOfTime::Seconds => time,
|
|
|
|
}
|
2020-02-11 20:35:22 +01:00
|
|
|
}
|
|
|
|
|
2020-07-03 19:00:05 +02:00
|
|
|
type Cx = UpdateWithCx<Message>;
|
2020-02-13 19:11:56 +01:00
|
|
|
|
|
|
|
// Mute a user with a replied message.
|
2020-06-24 19:43:21 +02:00
|
|
|
async fn mute_user(cx: &Cx, time: u32) -> ResponseResult<()> {
|
2020-02-18 23:54:41 +01:00
|
|
|
match cx.update.reply_to_message() {
|
2020-06-24 19:43:21 +02:00
|
|
|
Some(msg1) => {
|
|
|
|
cx.bot
|
|
|
|
.restrict_chat_member(
|
|
|
|
cx.update.chat_id(),
|
|
|
|
msg1.from().expect("Must be MessageKind::Common").id,
|
|
|
|
ChatPermissions::default(),
|
|
|
|
)
|
|
|
|
.until_date(cx.update.date + time as i32)
|
|
|
|
.send()
|
|
|
|
.await?;
|
|
|
|
}
|
2020-02-13 16:42:24 +01:00
|
|
|
None => {
|
2020-02-18 23:54:41 +01:00
|
|
|
cx.reply_to("Use this command in reply to another message")
|
2020-02-13 18:23:22 +01:00
|
|
|
.send()
|
|
|
|
.await?;
|
|
|
|
}
|
2020-02-13 16:42:24 +01:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-02-13 19:23:42 +01:00
|
|
|
// Kick a user with a replied message.
|
2020-02-18 23:54:41 +01:00
|
|
|
async fn kick_user(cx: &Cx) -> ResponseResult<()> {
|
|
|
|
match cx.update.reply_to_message() {
|
2020-02-13 16:42:24 +01:00
|
|
|
Some(mes) => {
|
2020-02-13 19:23:42 +01:00
|
|
|
// bot.unban_chat_member can also kicks a user from a group chat.
|
2020-02-18 23:54:41 +01:00
|
|
|
cx.bot
|
|
|
|
.unban_chat_member(cx.update.chat_id(), mes.from().unwrap().id)
|
2020-02-13 18:23:22 +01:00
|
|
|
.send()
|
|
|
|
.await?;
|
|
|
|
}
|
2020-02-13 16:42:24 +01:00
|
|
|
None => {
|
2020-02-18 23:54:41 +01:00
|
|
|
cx.reply_to("Use this command in reply to another message")
|
2020-02-13 18:23:22 +01:00
|
|
|
.send()
|
|
|
|
.await?;
|
2020-02-13 16:42:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-02-13 19:11:56 +01:00
|
|
|
// Ban a user with replied message.
|
2020-06-24 19:43:21 +02:00
|
|
|
async fn ban_user(cx: &Cx, time: u32) -> ResponseResult<()> {
|
2020-02-18 23:54:41 +01:00
|
|
|
match cx.update.reply_to_message() {
|
2020-06-24 19:43:21 +02:00
|
|
|
Some(message) => {
|
|
|
|
cx.bot
|
|
|
|
.kick_chat_member(
|
|
|
|
cx.update.chat_id(),
|
|
|
|
message.from().expect("Must be MessageKind::Common").id,
|
|
|
|
)
|
|
|
|
.until_date(cx.update.date + time as i32)
|
|
|
|
.send()
|
|
|
|
.await?;
|
|
|
|
}
|
2020-02-13 16:42:24 +01:00
|
|
|
None => {
|
2020-02-18 23:54:41 +01:00
|
|
|
cx.reply_to("Use this command in a reply to another message!")
|
2020-02-13 18:23:22 +01:00
|
|
|
.send()
|
|
|
|
.await?;
|
|
|
|
}
|
2020-02-13 16:42:24 +01:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-02-18 23:54:41 +01:00
|
|
|
async fn action(
|
2020-07-03 19:00:05 +02:00
|
|
|
cx: UpdateWithCx<Message>,
|
2020-02-18 23:54:41 +01:00
|
|
|
command: Command,
|
|
|
|
) -> ResponseResult<()> {
|
|
|
|
match command {
|
|
|
|
Command::Help => {
|
|
|
|
cx.answer(Command::descriptions()).send().await.map(|_| ())?
|
|
|
|
}
|
|
|
|
Command::Kick => kick_user(&cx).await?,
|
2020-06-24 19:43:21 +02:00
|
|
|
Command::Ban { time, unit } => {
|
|
|
|
ban_user(&cx, calc_restrict_time(time, unit)).await?
|
|
|
|
}
|
|
|
|
Command::Mute { time, unit } => {
|
|
|
|
mute_user(&cx, calc_restrict_time(time, unit)).await?
|
|
|
|
}
|
2020-02-18 23:54:41 +01:00
|
|
|
};
|
2020-02-11 20:35:22 +01:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-02-18 23:54:41 +01:00
|
|
|
async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
|
2020-02-19 10:53:54 +01:00
|
|
|
rx.filter(|cx| future::ready(cx.update.chat.is_group()))
|
2020-02-23 14:36:31 +01:00
|
|
|
.commands::<Command, &str>(panic!("Insert here your bot's name"))
|
2020-02-19 10:53:54 +01:00
|
|
|
// Execute all incoming commands concurrently:
|
2020-06-24 19:43:21 +02:00
|
|
|
.for_each_concurrent(None, |(cx, command)| async move {
|
|
|
|
action(cx, command).await.log_on_error().await;
|
2020-02-18 23:54:41 +01:00
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2020-02-11 20:35:22 +01:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
2020-02-18 23:54:41 +01:00
|
|
|
run().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn run() {
|
2020-02-13 18:23:22 +01:00
|
|
|
teloxide::enable_logging!();
|
2020-07-25 15:45:57 +02:00
|
|
|
log::info!("Starting admin_bot...");
|
2020-02-13 18:23:22 +01:00
|
|
|
|
|
|
|
let bot = Bot::from_env();
|
|
|
|
|
2020-02-18 23:54:41 +01:00
|
|
|
Dispatcher::new(bot).messages_handler(handle_commands).dispatch().await
|
2020-02-11 20:35:22 +01:00
|
|
|
}
|