mirror of
https://github.com/revanced/revanced-discord-bot.git
synced 2025-05-01 23:14:25 +02:00
chore(fmt): change to default rustfmt config (#12)
This commit is contained in:
parent
ecafabde54
commit
607638b99f
16
rustfmt.toml
16
rustfmt.toml
@ -1,16 +0,0 @@
|
|||||||
edition = "2018"
|
|
||||||
match_block_trailing_comma = true
|
|
||||||
newline_style = "Unix"
|
|
||||||
use_field_init_shorthand = true
|
|
||||||
use_small_heuristics = "Max"
|
|
||||||
use_try_shorthand = true
|
|
||||||
|
|
||||||
hard_tabs = true
|
|
||||||
format_code_in_doc_comments = true
|
|
||||||
group_imports = "StdExternalCrate"
|
|
||||||
imports_granularity = "Module"
|
|
||||||
imports_layout = "HorizontalVertical"
|
|
||||||
match_arm_blocks = true
|
|
||||||
normalize_comments = true
|
|
||||||
overflow_delimited_expr = true
|
|
||||||
struct_lit_single_line = false
|
|
@ -1,4 +1,4 @@
|
|||||||
pub fn init() {
|
pub fn init() {
|
||||||
// TODO: log to file
|
// TODO: log to file
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
}
|
}
|
||||||
|
397
src/main.rs
397
src/main.rs
@ -19,240 +19,259 @@ mod model;
|
|||||||
struct BotConfiguration;
|
struct BotConfiguration;
|
||||||
|
|
||||||
impl TypeMapKey for BotConfiguration {
|
impl TypeMapKey for BotConfiguration {
|
||||||
type Value = Arc<RwLock<Configuration>>;
|
type Value = Arc<RwLock<Configuration>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Handler;
|
pub struct Handler;
|
||||||
|
|
||||||
async fn get_configuration_lock(ctx: &Context) -> Arc<RwLock<Configuration>> {
|
async fn get_configuration_lock(ctx: &Context) -> Arc<RwLock<Configuration>> {
|
||||||
ctx.data
|
ctx.data
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
.get::<BotConfiguration>()
|
.get::<BotConfiguration>()
|
||||||
.expect("Expected Configuration in TypeMap.")
|
.expect("Expected Configuration in TypeMap.")
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_match(regex: &[Regex], text: &str) -> bool {
|
fn contains_match(regex: &[Regex], text: &str) -> bool {
|
||||||
regex.iter().any(|r| r.is_match(text))
|
regex.iter().any(|r| r.is_match(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_configuration() -> Configuration {
|
fn load_configuration() -> Configuration {
|
||||||
Configuration::load().expect("Failed to load configuration")
|
Configuration::load().expect("Failed to load configuration")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventHandler for Handler {
|
impl EventHandler for Handler {
|
||||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||||
debug!("Created an interaction: {:?}", interaction);
|
debug!("Created an interaction: {:?}", interaction);
|
||||||
|
|
||||||
if let Interaction::ApplicationCommand(command) = interaction {
|
if let Interaction::ApplicationCommand(command) = interaction {
|
||||||
let configuration_lock = get_configuration_lock(&ctx).await;
|
let configuration_lock = get_configuration_lock(&ctx).await;
|
||||||
let mut configuration = configuration_lock.write().await;
|
let mut configuration = configuration_lock.write().await;
|
||||||
|
|
||||||
let administrators = &configuration.administrators;
|
let administrators = &configuration.administrators;
|
||||||
let member = command.member.as_ref().unwrap();
|
let member = command.member.as_ref().unwrap();
|
||||||
let user_id = member.user.id.0;
|
let user_id = member.user.id.0;
|
||||||
let mut stop_command = false;
|
let mut stop_command = false;
|
||||||
let mut permission_granted = false;
|
let mut permission_granted = false;
|
||||||
|
|
||||||
// check if the user is an administrator
|
// check if the user is an administrator
|
||||||
if administrators.users.iter().any(|&id| user_id == id) {
|
if administrators.users.iter().any(|&id| user_id == id) {
|
||||||
permission_granted = true
|
permission_granted = true
|
||||||
}
|
}
|
||||||
// check if the user has an administrating role
|
// check if the user has an administrating role
|
||||||
if !permission_granted
|
if !permission_granted
|
||||||
&& administrators
|
&& administrators.roles.iter().any(|role_id| {
|
||||||
.roles
|
member
|
||||||
.iter()
|
.roles
|
||||||
.any(|role_id| member.roles.iter().any(|member_role| member_role == role_id))
|
.iter()
|
||||||
{
|
.any(|member_role| member_role == role_id)
|
||||||
permission_granted = true
|
})
|
||||||
}
|
{
|
||||||
|
permission_granted = true
|
||||||
|
}
|
||||||
|
|
||||||
let content = if permission_granted {
|
let content = if permission_granted {
|
||||||
match command.data.name.as_str() {
|
match command.data.name.as_str() {
|
||||||
"reload" => {
|
"reload" => {
|
||||||
debug!("{:?} reloaded the configuration.", command.user);
|
debug!("{:?} reloaded the configuration.", command.user);
|
||||||
|
|
||||||
let new_config = load_configuration();
|
let new_config = load_configuration();
|
||||||
|
|
||||||
configuration.administrators = new_config.administrators;
|
configuration.administrators = new_config.administrators;
|
||||||
configuration.message_responses = new_config.message_responses;
|
configuration.message_responses = new_config.message_responses;
|
||||||
configuration.thread_introductions = new_config.thread_introductions;
|
configuration.thread_introductions = new_config.thread_introductions;
|
||||||
|
|
||||||
"Successfully reloaded configuration.".to_string()
|
"Successfully reloaded configuration.".to_string()
|
||||||
},
|
}
|
||||||
"stop" => {
|
"stop" => {
|
||||||
debug!("{:?} stopped the bot.", command.user);
|
debug!("{:?} stopped the bot.", command.user);
|
||||||
stop_command = true;
|
stop_command = true;
|
||||||
"Stopped the bot.".to_string()
|
"Stopped the bot.".to_string()
|
||||||
},
|
}
|
||||||
_ => "Unknown command.".to_string(),
|
_ => "Unknown command.".to_string(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"You do not have permission to use this command.".to_string()
|
"You do not have permission to use this command.".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
// send the response
|
// send the response
|
||||||
if let Err(why) = command
|
if let Err(why) = command
|
||||||
.create_interaction_response(&ctx.http, |response| {
|
.create_interaction_response(&ctx.http, |response| {
|
||||||
response
|
response
|
||||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
.interaction_response_data(|message| {
|
.interaction_response_data(|message| {
|
||||||
message.content(content).flags(MessageFlags::EPHEMERAL)
|
message.content(content).flags(MessageFlags::EPHEMERAL)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
error!("Cannot respond to slash command: {}", why);
|
error!("Cannot respond to slash command: {}", why);
|
||||||
}
|
}
|
||||||
|
|
||||||
if stop_command {
|
if stop_command {
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn message(&self, ctx: Context, msg: Message) {
|
async fn message(&self, ctx: Context, msg: Message) {
|
||||||
debug!("Received message: {}", msg.content);
|
debug!("Received message: {}", msg.content);
|
||||||
if msg.guild_id.is_none() || msg.author.bot {
|
if msg.guild_id.is_none() || msg.author.bot {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message_response) =
|
if let Some(message_response) = get_configuration_lock(&ctx)
|
||||||
get_configuration_lock(&ctx).await.read().await.message_responses.iter().find(
|
.await
|
||||||
|&response| {
|
.read()
|
||||||
// check if the message was sent in a channel that is included in the responder
|
.await
|
||||||
response.includes.channels.iter().any(|&channel_id| channel_id == msg.channel_id.0)
|
.message_responses
|
||||||
// check if the message was sent by a user that is not excluded from the responder
|
.iter()
|
||||||
&& !response.excludes.roles.iter().any(|&role_id| role_id == msg.author.id.0)
|
.find(|&response| {
|
||||||
// check if the message does not match any of the excludes
|
// check if the message was sent in a channel that is included in the responder
|
||||||
&& !contains_match(&response.excludes.match_field, &msg.content)
|
response.includes.channels.iter().any(|&channel_id| channel_id == msg.channel_id.0)
|
||||||
// check if the message matches any of the includes
|
// check if the message was sent by a user that is not excluded from the responder
|
||||||
&& contains_match(&response.includes.match_field, &msg.content)
|
&& !response.excludes.roles.iter().any(|&role_id| role_id == msg.author.id.0)
|
||||||
},
|
// check if the message does not match any of the excludes
|
||||||
) {
|
&& !contains_match(&response.excludes.match_field, &msg.content)
|
||||||
let min_age = message_response.condition.user.server_age;
|
// check if the message matches any of the includes
|
||||||
|
&& contains_match(&response.includes.match_field, &msg.content)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let min_age = message_response.condition.user.server_age;
|
||||||
|
|
||||||
if min_age != 0 {
|
if min_age != 0 {
|
||||||
let joined_at = ctx
|
let joined_at = ctx
|
||||||
.http
|
.http
|
||||||
.get_member(msg.guild_id.unwrap().0, msg.author.id.0)
|
.get_member(msg.guild_id.unwrap().0, msg.author.id.0)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.joined_at
|
.joined_at
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unix_timestamp();
|
.unix_timestamp();
|
||||||
|
|
||||||
let must_joined_at =
|
let must_joined_at =
|
||||||
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(joined_at, 0), Utc);
|
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(joined_at, 0), Utc);
|
||||||
let but_joined_at = Utc::now() - Duration::days(min_age);
|
let but_joined_at = Utc::now() - Duration::days(min_age);
|
||||||
|
|
||||||
if must_joined_at <= but_joined_at {
|
if must_joined_at <= but_joined_at {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.send_message(&ctx.http, |m| {
|
.send_message(&ctx.http, |m| {
|
||||||
m.reference_message(&msg);
|
m.reference_message(&msg);
|
||||||
match &message_response.response.embed {
|
match &message_response.response.embed {
|
||||||
Some(embed) => m.embed(|e| {
|
Some(embed) => m.embed(|e| {
|
||||||
e.title(&embed.title)
|
e.title(&embed.title)
|
||||||
.description(&embed.description)
|
.description(&embed.description)
|
||||||
.color(embed.color)
|
.color(embed.color)
|
||||||
.fields(embed.fields.iter().map(|field| {
|
.fields(embed.fields.iter().map(|field| {
|
||||||
(field.name.clone(), field.value.clone(), field.inline)
|
(field.name.clone(), field.value.clone(), field.inline)
|
||||||
}))
|
}))
|
||||||
.footer(|f| {
|
.footer(|f| {
|
||||||
f.text(&embed.footer.text);
|
f.text(&embed.footer.text);
|
||||||
f.icon_url(&embed.footer.icon_url)
|
f.icon_url(&embed.footer.icon_url)
|
||||||
})
|
})
|
||||||
.thumbnail(&embed.thumbnail.url)
|
.thumbnail(&embed.thumbnail.url)
|
||||||
.image(&embed.image.url)
|
.image(&embed.image.url)
|
||||||
.author(|a| {
|
.author(|a| {
|
||||||
a.name(&embed.author.name).icon_url(&embed.author.icon_url)
|
a.name(&embed.author.name).icon_url(&embed.author.icon_url)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
None => m.content(message_response.response.message.as_ref().unwrap()),
|
None => m.content(message_response.response.message.as_ref().unwrap()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.expect("Could not reply to message author.");
|
.expect("Could not reply to message author.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn thread_create(&self, ctx: Context, thread: GuildChannel) {
|
async fn thread_create(&self, ctx: Context, thread: GuildChannel) {
|
||||||
if thread.member.is_some() {
|
if thread.member.is_some() {
|
||||||
debug!("Thread was joined. Block dispatch.");
|
debug!("Thread was joined. Block dispatch.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Thread created: {:?}", thread);
|
debug!("Thread created: {:?}", thread);
|
||||||
|
|
||||||
let configuration_lock = get_configuration_lock(&ctx).await;
|
let configuration_lock = get_configuration_lock(&ctx).await;
|
||||||
let configuration = configuration_lock.read().await;
|
let configuration = configuration_lock.read().await;
|
||||||
|
|
||||||
if let Some(introducer) = &configuration.thread_introductions.iter().find(|introducer| {
|
if let Some(introducer) = &configuration
|
||||||
introducer.channels.iter().any(|channel_id| *channel_id == thread.parent_id.unwrap().0)
|
.thread_introductions
|
||||||
}) {
|
.iter()
|
||||||
if let Err(why) =
|
.find(|introducer| {
|
||||||
thread.say(&ctx.http, &introducer.response.message.as_ref().unwrap()).await
|
introducer
|
||||||
{
|
.channels
|
||||||
error!("Error sending message: {:?}", why);
|
.iter()
|
||||||
}
|
.any(|channel_id| *channel_id == thread.parent_id.unwrap().0)
|
||||||
}
|
})
|
||||||
}
|
{
|
||||||
|
if let Err(why) = thread
|
||||||
|
.say(&ctx.http, &introducer.response.message.as_ref().unwrap())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
error!("Error sending message: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||||
info!("Connected as {}", ready.user.name);
|
info!("Connected as {}", ready.user.name);
|
||||||
|
|
||||||
for (cmd, description) in
|
for (cmd, description) in [
|
||||||
[("repload", "Reloads the configuration."), ("stop", "Stop the Discord bot.")]
|
("repload", "Reloads the configuration."),
|
||||||
{
|
("stop", "Stop the Discord bot."),
|
||||||
Command::create_global_application_command(&ctx.http, |command| {
|
] {
|
||||||
command.name(cmd).description(description)
|
Command::create_global_application_command(&ctx.http, |command| {
|
||||||
})
|
command.name(cmd).description(description)
|
||||||
.await
|
})
|
||||||
.expect("Could not create command.");
|
.await
|
||||||
}
|
.expect("Could not create command.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
// Initialize the logging framework.
|
// Initialize the logging framework.
|
||||||
logger::init();
|
logger::init();
|
||||||
|
|
||||||
// Set up the configuration.
|
// Set up the configuration.
|
||||||
let configuration = load_configuration();
|
let configuration = load_configuration();
|
||||||
|
|
||||||
// Load environment variables from .env file
|
// Load environment variables from .env file
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
|
|
||||||
// Get the Discord authorization token.
|
// Get the Discord authorization token.
|
||||||
let token = env::var("DISCORD_AUTHORIZATION_TOKEN")
|
let token = env::var("DISCORD_AUTHORIZATION_TOKEN")
|
||||||
.expect("Could not load Discord authorization token");
|
.expect("Could not load Discord authorization token");
|
||||||
if token.len() != 70 {
|
if token.len() != 70 {
|
||||||
error!("Invalid Discord authorization token.");
|
error!("Invalid Discord authorization token.");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Discord bot client.
|
// Create the Discord bot client.
|
||||||
let mut client = Client::builder(
|
let mut client = Client::builder(
|
||||||
&token,
|
&token,
|
||||||
GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT,
|
GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT,
|
||||||
)
|
)
|
||||||
.event_handler(Handler)
|
.event_handler(Handler)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create client");
|
.expect("Failed to create client");
|
||||||
|
|
||||||
// Save the configuration.
|
// Save the configuration.
|
||||||
client.data.write().await.insert::<BotConfiguration>(Arc::new(RwLock::new(configuration)));
|
client
|
||||||
|
.data
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.insert::<BotConfiguration>(Arc::new(RwLock::new(configuration)));
|
||||||
|
|
||||||
// Start the Discord bot.
|
// Start the Discord bot.
|
||||||
client.start().await.expect("failed to start discord bot");
|
client.start().await.expect("failed to start discord bot");
|
||||||
|
|
||||||
info!("Client started.");
|
info!("Client started.");
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{Read, Result, Write},
|
io::{Read, Result, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
use dirs::config_dir;
|
use dirs::config_dir;
|
||||||
@ -10,142 +10,147 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
pub administrators: Administrators,
|
pub administrators: Administrators,
|
||||||
pub thread_introductions: Vec<Introduction>,
|
pub thread_introductions: Vec<Introduction>,
|
||||||
pub message_responses: Vec<MessageResponse>,
|
pub message_responses: Vec<MessageResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONFIG_PATH: &str = "configuration.json";
|
const CONFIG_PATH: &str = "configuration.json";
|
||||||
|
|
||||||
impl Configuration {
|
impl Configuration {
|
||||||
fn save(&self) -> Result<()> {
|
fn save(&self) -> Result<()> {
|
||||||
let sys_config_dir = config_dir().expect("find config dir");
|
let sys_config_dir = config_dir().expect("find config dir");
|
||||||
|
|
||||||
fs::create_dir_all(format!("{}/revanced-discord-bot", sys_config_dir.to_string_lossy()))
|
fs::create_dir_all(format!(
|
||||||
.expect("create config dir");
|
"{}/revanced-discord-bot",
|
||||||
|
sys_config_dir.to_string_lossy()
|
||||||
|
))
|
||||||
|
.expect("create config dir");
|
||||||
|
|
||||||
let mut file = File::create(CONFIG_PATH)?;
|
let mut file = File::create(CONFIG_PATH)?;
|
||||||
let json = serde_json::to_string_pretty(&self)?;
|
let json = serde_json::to_string_pretty(&self)?;
|
||||||
file.write_all(json.as_bytes())?;
|
file.write_all(json.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<Configuration> {
|
pub fn load() -> Result<Configuration> {
|
||||||
let sys_config_dir = config_dir().expect("Can not find the configuration directory.");
|
let sys_config_dir = config_dir().expect("Can not find the configuration directory.");
|
||||||
let sys_config =
|
let sys_config = format!(
|
||||||
format!("{}/revanced-discord-bot/{CONFIG_PATH}", sys_config_dir.to_string_lossy());
|
"{}/revanced-discord-bot/{CONFIG_PATH}",
|
||||||
|
sys_config_dir.to_string_lossy()
|
||||||
|
);
|
||||||
|
|
||||||
// config file in current dir
|
// config file in current dir
|
||||||
let mut file = if Path::new(CONFIG_PATH).exists() {
|
let mut file = if Path::new(CONFIG_PATH).exists() {
|
||||||
File::open(CONFIG_PATH)?
|
File::open(CONFIG_PATH)?
|
||||||
}
|
}
|
||||||
// config file in system dir (on *nix: `~/.config/revanced-discord-bot/`)
|
// config file in system dir (on *nix: `~/.config/revanced-discord-bot/`)
|
||||||
else if Path::new(&sys_config).exists() {
|
else if Path::new(&sys_config).exists() {
|
||||||
File::open(sys_config)?
|
File::open(sys_config)?
|
||||||
}
|
}
|
||||||
// create defalt config
|
// create defalt config
|
||||||
else {
|
else {
|
||||||
let default_config = Configuration::default();
|
let default_config = Configuration::default();
|
||||||
default_config.save()?;
|
default_config.save()?;
|
||||||
|
|
||||||
File::open(sys_config)?
|
File::open(sys_config)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
file.read_to_string(&mut buf)?;
|
file.read_to_string(&mut buf)?;
|
||||||
|
|
||||||
Ok(serde_json::from_str(&buf)?)
|
Ok(serde_json::from_str(&buf)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
pub struct Administrators {
|
pub struct Administrators {
|
||||||
pub roles: Vec<u64>,
|
pub roles: Vec<u64>,
|
||||||
pub users: Vec<u64>,
|
pub users: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Introduction {
|
pub struct Introduction {
|
||||||
pub channels: Vec<u64>,
|
pub channels: Vec<u64>,
|
||||||
pub response: Response,
|
pub response: Response,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct MessageResponse {
|
pub struct MessageResponse {
|
||||||
pub includes: Includes,
|
pub includes: Includes,
|
||||||
pub excludes: Excludes,
|
pub excludes: Excludes,
|
||||||
pub condition: Condition,
|
pub condition: Condition,
|
||||||
pub response: Response,
|
pub response: Response,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
pub embed: Option<Embed>,
|
pub embed: Option<Embed>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Embed {
|
pub struct Embed {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub color: i32,
|
pub color: i32,
|
||||||
pub fields: Vec<Field>,
|
pub fields: Vec<Field>,
|
||||||
pub footer: Footer,
|
pub footer: Footer,
|
||||||
pub image: Image,
|
pub image: Image,
|
||||||
pub thumbnail: Thumbnail,
|
pub thumbnail: Thumbnail,
|
||||||
pub author: Author,
|
pub author: Author,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
pub inline: bool,
|
pub inline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Footer {
|
pub struct Footer {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub icon_url: String,
|
pub icon_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Thumbnail {
|
pub struct Thumbnail {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Author {
|
pub struct Author {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub icon_url: String,
|
pub icon_url: String,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Includes {
|
pub struct Includes {
|
||||||
pub channels: Vec<u64>,
|
pub channels: Vec<u64>,
|
||||||
#[serde(rename = "match", with = "serde_regex")]
|
#[serde(rename = "match", with = "serde_regex")]
|
||||||
pub match_field: Vec<Regex>,
|
pub match_field: Vec<Regex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Excludes {
|
pub struct Excludes {
|
||||||
pub roles: Vec<u64>,
|
pub roles: Vec<u64>,
|
||||||
#[serde(rename = "match", with = "serde_regex")]
|
#[serde(rename = "match", with = "serde_regex")]
|
||||||
pub match_field: Vec<Regex>,
|
pub match_field: Vec<Regex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Condition {
|
pub struct Condition {
|
||||||
pub user: User,
|
pub user: User,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub server_age: i64,
|
pub server_age: i64,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user