updated admin_command example

This commit is contained in:
p0lunin 2020-06-24 20:43:21 +03:00
parent 9944524e34
commit 33f92f9ea0

View file

@ -1,4 +1,4 @@
// TODO: simplify this and use typed command variants (see https://github.com/teloxide/teloxide/issues/152).
use std::str::FromStr;
use teloxide::{
prelude::*, types::ChatPermissions, utils::command::BotCommand,
@ -18,82 +18,68 @@ use futures::future;
#[derive(BotCommand)]
#[command(
rename = "lowercase",
description = "Use commands in format /%command% %num% %unit%"
description = "Use commands in format /%command% %num% %unit%",
parse_with = "split"
)]
enum Command {
#[command(description = "kick user from chat.")]
Kick,
#[command(description = "ban user in chat.")]
Ban,
Ban {
time: u32,
unit: UnitOfTime,
},
#[command(description = "mute user in chat.")]
Mute,
Mute {
time: u32,
unit: UnitOfTime,
},
Help,
}
enum UnitOfTime {
Seconds,
Minutes,
Hours,
}
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"),
}
}
}
// Calculates time of user restriction.
fn calc_restrict_time(num: i32, unit: &str) -> Result<i32, &str> {
fn calc_restrict_time(time: u32, unit: UnitOfTime) -> u32 {
match unit {
"h" | "hours" => Ok(num * 3600),
"m" | "minutes" => Ok(num * 60),
"s" | "seconds" => Ok(num),
_ => Err("Allowed units: h, m, s"),
UnitOfTime::Hours => time * 3600,
UnitOfTime::Minutes => time * 60,
UnitOfTime::Seconds => time,
}
}
// Parse arguments after a command.
fn parse_args(args: &[String]) -> Result<(i32, &str), &str> {
let num = match args.get(0) {
Some(s) => s,
None => return Err("Use command in format /%command% %num% %unit%"),
};
let unit = match args.get(1) {
Some(s) => s,
None => return Err("Use command in format /%command% %num% %unit%"),
};
match num.parse::<i32>() {
Ok(n) => Ok((n, unit)),
Err(_) => Err("input positive number!"),
}
}
// Parse arguments into a user restriction duration.
fn parse_time_restrict(args: &[String]) -> Result<i32, &str> {
let (num, unit) = parse_args(args)?;
calc_restrict_time(num, unit)
}
type Cx = DispatcherHandlerCx<Message>;
// Mute a user with a replied message.
async fn mute_user(cx: &Cx, args: &[String]) -> ResponseResult<()> {
async fn mute_user(cx: &Cx, time: u32) -> ResponseResult<()> {
match cx.update.reply_to_message() {
Some(msg1) => match parse_time_restrict(args) {
// Mute user temporarily...
Ok(time) => {
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)
.send()
.await?;
}
// ...or permanently
Err(_) => {
cx.bot
.restrict_chat_member(
cx.update.chat_id(),
msg1.from().unwrap().id,
ChatPermissions::default(),
)
.send()
.await?;
}
},
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?;
}
None => {
cx.reply_to("Use this command in reply to another message")
.send()
@ -123,31 +109,18 @@ async fn kick_user(cx: &Cx) -> ResponseResult<()> {
}
// Ban a user with replied message.
async fn ban_user(cx: &Cx, args: &[String]) -> ResponseResult<()> {
async fn ban_user(cx: &Cx, time: u32) -> ResponseResult<()> {
match cx.update.reply_to_message() {
Some(message) => match parse_time_restrict(args) {
// Mute user temporarily...
Ok(time) => {
cx.bot
.kick_chat_member(
cx.update.chat_id(),
message.from().expect("Must be MessageKind::Common").id,
)
.until_date(cx.update.date + time)
.send()
.await?;
}
// ...or permanently
Err(_) => {
cx.bot
.kick_chat_member(
cx.update.chat_id(),
message.from().unwrap().id,
)
.send()
.await?;
}
},
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?;
}
None => {
cx.reply_to("Use this command in a reply to another message!")
.send()
@ -160,15 +133,18 @@ async fn ban_user(cx: &Cx, args: &[String]) -> ResponseResult<()> {
async fn action(
cx: DispatcherHandlerCx<Message>,
command: Command,
args: &[String],
) -> ResponseResult<()> {
match command {
Command::Help => {
cx.answer(Command::descriptions()).send().await.map(|_| ())?
}
Command::Kick => kick_user(&cx).await?,
Command::Ban => ban_user(&cx, args).await?,
Command::Mute => mute_user(&cx, args).await?,
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?
}
};
Ok(())
@ -181,8 +157,8 @@ async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
// Only iterate through commands in a proper format:
.commands::<Command, &str>(panic!("Insert here your bot's name"))
// Execute all incoming commands concurrently:
.for_each_concurrent(None, |(cx, command, args)| async move {
action(cx, command, &args).await.log_on_error().await;
.for_each_concurrent(None, |(cx, command)| async move {
action(cx, command).await.log_on_error().await;
})
.await;
}