Admin commands

Owner-only commands
This commit is contained in:
Oupson 2020-08-25 23:33:11 +02:00
parent 1c28b1238c
commit 5e125052c5
5 changed files with 261 additions and 83 deletions

View File

@ -1 +1,97 @@
use crate::debugln;
use serenity::{
framework::standard::{
macros::{command, group},
CommandResult,
},
model::prelude::*,
prelude::*,
};
#[group]
#[commands(ban, kick)]
pub struct Admin;
#[command]
#[description = "Kick an user"]
#[only_in(guilds)]
#[required_permissions("KICK_MEMBERS")]
async fn kick(ctx: &Context, msg: &Message) -> CommandResult {
// TODO CACHE ?
if let Some(sender_member) = msg.member(ctx).await {
for user in &msg.mentions {
if let Some(member) = ctx.cache.member(msg.guild_id.unwrap(), user.id).await {
debugln!("Kicking {:?}", user);
let kick = if let Some(role_member) = sender_member.highest_role_info(ctx).await {
if let Some(role) = member.highest_role_info(ctx).await {
role_member.1 > role.1
} else {
true
}
} else {
true
};
if kick {
member.kick(ctx).await?;
} else {
msg.channel_id
.say(
ctx,
&format!(
"Error, you can't kick {}",
if let Some(nick) = member.nick {
nick
} else {
user.name.clone()
}
),
)
.await?;
}
}
}
}
Ok(())
}
#[command]
#[description = "Ban an user"]
#[only_in(guilds)]
#[required_permissions("BAN_MEMBERS")]
async fn ban(ctx: &Context, msg: &Message) -> CommandResult {
// TODO CACHE ?
if let Some(sender_member) = msg.member(ctx).await {
for user in &msg.mentions {
if let Some(member) = ctx.cache.member(msg.guild_id.unwrap(), user.id).await {
debugln!("Kicking {:?}", user);
let kick = if let Some(role_member) = sender_member.highest_role_info(ctx).await {
if let Some(role) = member.highest_role_info(ctx).await {
role_member.1 > role.1
} else {
true
}
} else {
true
};
if kick {
member.ban(ctx, 0).await?;
} else {
msg.channel_id
.say(
ctx,
&format!(
"Error, you can't ban {}",
if let Some(nick) = member.nick {
nick
} else {
user.name.clone()
}
),
)
.await?;
}
}
}
}
Ok(())
}

View File

@ -1,6 +1,7 @@
use crate::{api, debugln};
use crate::{api, debugln, ShardManagerContainer};
use futures::StreamExt;
use serenity::{
client::bridge::gateway::ShardId,
framework::standard::{
macros::{command, group},
ArgError, Args, CommandResult,
@ -10,7 +11,7 @@ use serenity::{
};
#[group]
#[commands(longcode, image, older, ping, invite, infos, error, send_message)]
#[commands(error, image, infos, invite, latency, longcode, older, ping)]
pub struct General;
#[command]
@ -19,6 +20,45 @@ pub async fn error(_ctx: &Context, _msg: &Message) -> CommandResult {
Ok(())
}
#[command]
async fn latency(ctx: &Context, msg: &Message) -> CommandResult {
// The shard manager is an interface for mutating, stopping, restarting, and
// retrieving information about shards.
let data = ctx.data.read().await;
let shard_manager = match data.get::<ShardManagerContainer>() {
Some(v) => v,
None => {
let _ = msg
.reply(ctx, "There was a problem getting the shard manager")
.await;
return Ok(());
}
};
let manager = shard_manager.lock().await;
let runners = manager.runners.lock().await;
// Shards are backed by a "shard runner" responsible for processing events
// over the shard, so we'll get the information about the shard runner for
// the shard this command was sent over.
let runner = match runners.get(&ShardId(ctx.shard_id)) {
Some(runner) => runner,
None => {
let _ = msg.reply(ctx, "No shard found");
return Ok(());
}
};
let _ = msg
.reply(ctx, &format!("The shard latency is {:?}", runner.latency))
.await;
Ok(())
}
#[command]
#[description = "Split a huge code"]
#[bucket = "longcode"]
@ -66,6 +106,58 @@ async fn _longcode(ctx: &Context, msg: &Message, mut args: Args) -> crate::comma
Ok(())
}
#[command]
#[description = "Print bot infos"]
async fn infos(ctx: &Context, msg: &Message) -> CommandResult {
let current_user = ctx.http.get_current_user().await;
msg.channel_id
.send_message(ctx, |m| {
m.embed(|e| {
e.title(format!(
"{} v{}, by {}",
option_env!("CARGO_PKG_NAME").unwrap_or("unknown"),
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
option_env!("CARGO_PKG_AUTHORS").unwrap_or("unknows")
))
.description(format!(
concat!(
"Features : {:?}\n",
"Mode : {}\n",
"Source code : https://git.oupsman.fr/oupson/discord_rusty_bot"
),
get_features(),
if cfg!(debug_assertions) {
"debug"
} else {
"release"
},
))
.colour((247, 76, 0))
.footer(|f| {
if let Ok(user) = &current_user {
let mut f = f.text(&user.name);
if let Some(avatar) = user.avatar_url() {
f = f.icon_url(avatar);
}
f
} else {
f
}
})
})
})
.await?;
Ok(())
}
fn get_features<'m>() -> Vec<&'m str> {
let mut res = Vec::new();
if cfg!(feature = "music") {
res.push("music");
}
res
}
#[command]
#[description("Print the bot invite link")]
async fn invite(ctx: &Context, msg: &Message) -> CommandResult {
@ -82,22 +174,6 @@ async fn invite(ctx: &Context, msg: &Message) -> CommandResult {
Ok(())
}
#[command]
#[description("Pong !")]
async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
let now = std::time::Instant::now();
msg.channel_id.say(&ctx.http, "Pong!").await?;
let elapsed = now.elapsed();
msg.channel_id
.say(
&ctx.http,
format!("Time elapsed : {}ms", elapsed.as_millis()),
)
.await?;
Ok(())
}
#[command]
#[description = "Find who is the older"]
pub async fn older(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
@ -153,55 +229,19 @@ async fn _older(ctx: &Context, msg: &Message, mut args: Args) -> crate::commands
}
#[command]
#[description = "Print bot infos"]
async fn infos(ctx: &Context, msg: &Message) -> CommandResult {
let current_user = ctx.http.get_current_user().await;
#[description("Pong !")]
async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
let now = std::time::Instant::now();
msg.channel_id.say(&ctx.http, "Pong!").await?;
let elapsed = now.elapsed();
msg.channel_id
.send_message(ctx, |m| {
m.embed(|e| {
e.title(format!(
"{} v{}, by {}",
option_env!("CARGO_PKG_NAME").unwrap_or("unknown"),
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
option_env!("CARGO_PKG_AUTHORS").unwrap_or("unknows")
))
.description(format!(
concat!(
"Features : {:?}\n",
"Mode : {}\n",
"Source code : https://git.oupsman.fr/oupson/discord_rusty_bot"
),
get_features(),
if cfg!(debug_assertions) {
"debug"
} else {
"release"
},
))
.colour((247, 76, 0))
.footer(|f| {
if let Ok(user) = &current_user {
let mut f = f.text(&user.name);
if let Some(avatar) = user.avatar_url() {
f = f.icon_url(avatar);
}
f
} else {
f
}
})
})
})
.say(
&ctx.http,
format!("Time elapsed : {}ms", elapsed.as_millis()),
)
.await?;
Ok(())
}
fn get_features<'m>() -> Vec<&'m str> {
let mut res = Vec::new();
if cfg!(feature = "music") {
res.push("music");
}
res
Ok(())
}
#[command]
@ -288,13 +328,3 @@ impl std::str::FromStr for Image {
}
}
}
#[command]
#[owners_only]
async fn send_message(ctx: &Context, _msg: &Message, mut args: Args) -> CommandResult {
let channel_id = args.single::<ChannelId>()?;
let message = args.single::<String>()?;
debugln!("Send {} into {:?}", message, channel_id);
channel_id.say(ctx, message).await?;
Ok(())
}

View File

@ -1,5 +1,6 @@
pub(crate) mod admin;
pub(crate) mod general;
pub(crate) mod owner;
pub(crate) mod roulette;
#[cfg(feature = "music")]

32
src/commands/owner.rs Normal file
View File

@ -0,0 +1,32 @@
use crate::debugln;
use serenity::{
framework::standard::{
macros::{command, group},
Args, CommandResult,
},
model::prelude::*,
prelude::*,
};
use std::convert::TryFrom;
#[group]
#[commands(leave, send_message)]
pub(crate) struct Owner;
#[command]
#[owners_only]
pub async fn leave(ctx: &Context, _msg: &Message, mut args: Args) -> CommandResult {
let guild = GuildId::try_from(args.single::<u64>()?)?;
guild.leave(&ctx.http).await?;
Ok(())
}
#[command]
#[owners_only]
async fn send_message(ctx: &Context, _msg: &Message, mut args: Args) -> CommandResult {
let channel_id = args.single::<ChannelId>()?;
let message = args.single::<String>()?;
debugln!("Send {} into {:?}", message, channel_id);
channel_id.say(ctx, message).await?;
Ok(())
}

View File

@ -1,5 +1,7 @@
use crate::commands::{
admin::ADMIN_GROUP,
general::GENERAL_GROUP,
owner::OWNER_GROUP,
roulette::{BulletsContainer, NonKickGuildsContainer, ROULETTE_GROUP},
};
use async_trait::async_trait;
@ -111,8 +113,10 @@ async fn main() -> IoResult<()> {
.on_dispatch_error(dispatch_error)
.after(after_hook)
.help(&MY_HELP)
.group(&ADMIN_GROUP)
.group(&GENERAL_GROUP)
.group(&ROULETTE_GROUP);
.group(&ROULETTE_GROUP)
.group(&OWNER_GROUP);
#[cfg(feature = "music")]
{
@ -294,14 +298,29 @@ async fn normal_message(_ctx: &Context, msg: &Message) {
#[hook]
async fn dispatch_error(ctx: &Context, msg: &Message, error: DispatchError) {
debugln!("Dispatch error : {:?}", error);
if let DispatchError::Ratelimited(seconds) = error {
let _ = msg
.channel_id
.say(
&ctx.http,
&format!("Try this again in {} seconds.", seconds),
)
.await;
match error {
DispatchError::Ratelimited(seconds) => {
let _ = msg
.channel_id
.say(
&ctx.http,
&format!("Try this again in {} seconds.", seconds),
)
.await;
}
DispatchError::OnlyForOwners => {
let _ = msg
.channel_id
.say(&ctx.http, "Error : only the owner can call this command")
.await;
}
DispatchError::LackingPermissions(perms) => {
let _ = msg
.channel_id
.say(&ctx.http, &format!("Error, only {:?} can do that", perms))
.await;
}
_ => {}
}
}