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