WIP
This commit is contained in:
parent
3a437db2b6
commit
b34da70c8b
|
@ -6,16 +6,18 @@ use crate::discord::event_handler::Handler;
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
serenity_client: SerenityClient,
|
serenity_client: SerenityClient,
|
||||||
database_client: DatabaseClient,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Client {
|
impl Client {
|
||||||
async fn new() -> Self {
|
pub async fn new() -> Self {
|
||||||
|
let mut database_client = DatabaseClient::new();
|
||||||
|
database_client.connect().await;
|
||||||
|
|
||||||
let discord_token = get_env_variable("DISCORD_TOKEN");
|
let discord_token = get_env_variable("DISCORD_TOKEN");
|
||||||
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
|
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
|
||||||
let database_client = DatabaseClient::new();
|
|
||||||
let event_handler = Handler {
|
let event_handler = Handler {
|
||||||
database: &database_client,
|
database: database_client,
|
||||||
};
|
};
|
||||||
|
|
||||||
let serenity_client = match SerenityClient::builder(discord_token, intents)
|
let serenity_client = match SerenityClient::builder(discord_token, intents)
|
||||||
|
@ -26,15 +28,10 @@ impl<'a> Client {
|
||||||
Err(e) => panic!("Failed to instantiate Discord Client: {e}"),
|
Err(e) => panic!("Failed to instantiate Discord Client: {e}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Client {
|
Client { serenity_client }
|
||||||
serenity_client,
|
|
||||||
database_client,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(&mut self) {
|
pub async fn start(&mut self) {
|
||||||
self.database_client.connect().await;
|
|
||||||
|
|
||||||
if let Err(e) = self.serenity_client.start().await {
|
if let Err(e) = self.serenity_client.start().await {
|
||||||
panic!("Could not connect the bot: {e}");
|
panic!("Could not connect the bot: {e}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Module for database interaction and wrapping
|
//! Module for database interaction and wrapping
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
mod models;
|
pub mod models;
|
||||||
|
|
||||||
pub use client::Client;
|
pub use client::Client;
|
||||||
|
|
|
@ -116,7 +116,7 @@ impl Client {
|
||||||
pub async fn get_all<T: YorokobotModel + for<'de> Deserialize<'de>>(
|
pub async fn get_all<T: YorokobotModel + for<'de> Deserialize<'de>>(
|
||||||
&self,
|
&self,
|
||||||
filter: Option<Document>,
|
filter: Option<Document>,
|
||||||
) {
|
) -> Vec<T> {
|
||||||
let mut result: Vec<T> = vec![];
|
let mut result: Vec<T> = vec![];
|
||||||
|
|
||||||
let mut cursor = match filter {
|
let mut cursor = match filter {
|
||||||
|
@ -129,6 +129,8 @@ impl Client {
|
||||||
result
|
result
|
||||||
.push(from_bson(Bson::Document(document)).expect("Could not deserialize document"));
|
.push(from_bson(Bson::Document(document)).expect("Could not deserialize document"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -5,46 +5,25 @@
|
||||||
use mongodb::bson::oid::ObjectId;
|
use mongodb::bson::oid::ObjectId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub const COLLECTIONS_NAMES: [&str; 2] = ["guilds", "tags"];
|
pub const COLLECTIONS_NAMES: [&str; 1] = ["tags"];
|
||||||
|
|
||||||
pub trait YorokobotModel {
|
pub trait YorokobotModel {
|
||||||
fn get_collection_name() -> String;
|
fn get_collection_name() -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Settings for a server
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct GuildSettings {
|
|
||||||
admin_only_can_tag: bool,
|
|
||||||
server_ban_list: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Server infos
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct Guild {
|
|
||||||
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
|
|
||||||
id: Option<ObjectId>,
|
|
||||||
discord_guild_id: String,
|
|
||||||
bot_settings: GuildSettings,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tags
|
/// Tags
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
|
||||||
id: Option<ObjectId>,
|
pub id: Option<ObjectId>,
|
||||||
name: String,
|
pub name: String,
|
||||||
guild: String,
|
pub guild_id: String,
|
||||||
is_nsfw: bool,
|
pub is_nsfw: bool,
|
||||||
subscribers: Vec<String>,
|
pub subscribers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YorokobotModel for Guild {
|
|
||||||
fn get_collection_name() -> String {
|
|
||||||
"guilds".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl YorokobotModel for Tag {
|
impl YorokobotModel for Tag {
|
||||||
fn get_collection_name() -> String {
|
fn get_collection_name() -> String {
|
||||||
"traits".to_string()
|
"tags".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
pub mod event_handler;
|
pub mod event_handler;
|
||||||
|
|
||||||
|
mod commands;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod bulk_create_tag;
|
||||||
|
pub mod create_tag;
|
||||||
|
pub mod delete_tag;
|
||||||
|
pub mod list_tags;
|
||||||
|
pub mod source_code;
|
22
src/discord/commands/bulk_create_tag.rs
Normal file
22
src/discord/commands/bulk_create_tag.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use serenity::{builder::CreateApplicationCommand, model::prelude::command::CommandOptionType};
|
||||||
|
|
||||||
|
pub fn register(
|
||||||
|
command: &mut CreateApplicationCommand,
|
||||||
|
max_args_number: u32,
|
||||||
|
) -> &mut CreateApplicationCommand {
|
||||||
|
command
|
||||||
|
.name("bulk_create_tag")
|
||||||
|
.description("Add multiples tags");
|
||||||
|
|
||||||
|
for i in 0..max_args_number {
|
||||||
|
command.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name(format!("tag{}", i + 1))
|
||||||
|
.description("A new tag to add")
|
||||||
|
.kind(CommandOptionType::String)
|
||||||
|
.required(i == 0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
command
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
|
||||||
|
use serenity::{
|
||||||
|
builder::{CreateApplicationCommand, CreateInteractionResponseData},
|
||||||
|
model::{
|
||||||
|
application::interaction::application_command::ApplicationCommandInteraction,
|
||||||
|
prelude::{
|
||||||
|
command::CommandOptionType, interaction::application_command::CommandDataOptionValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::database::{models::Tag, Client as DatabaseClient};
|
||||||
|
|
||||||
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||||
|
command
|
||||||
|
.name("create_tag")
|
||||||
|
.description("Add a new tag")
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("tag")
|
||||||
|
.description("The tag to create")
|
||||||
|
.kind(CommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run<'a, 'b>(
|
||||||
|
response: &'a mut CreateInteractionResponseData<'b>,
|
||||||
|
command: &ApplicationCommandInteraction,
|
||||||
|
database: &DatabaseClient,
|
||||||
|
) -> &'a mut CreateInteractionResponseData<'b> {
|
||||||
|
let arg = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.get(0)
|
||||||
|
.expect("Missing option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Could not deserialize option");
|
||||||
|
|
||||||
|
let guild_id = command
|
||||||
|
.guild_id
|
||||||
|
.expect("Could not fetch guild id")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
if let CommandDataOptionValue::String(tag_name) = arg {
|
||||||
|
let matching_tags = database
|
||||||
|
.get_all::<Tag>(Some(doc! {"name": tag_name, "guild_id": guild_id.as_str()}))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if !matching_tags.is_empty() {
|
||||||
|
response.content("This tag already exist for this server");
|
||||||
|
} else {
|
||||||
|
match database
|
||||||
|
.insert_one(Tag {
|
||||||
|
id: None,
|
||||||
|
name: tag_name.to_string(),
|
||||||
|
guild_id: guild_id.clone(),
|
||||||
|
is_nsfw: false,
|
||||||
|
subscribers: vec![],
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => response.content("Tag successfully created."),
|
||||||
|
Err(_) => response.content("Error creating the tag"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
}
|
14
src/discord/commands/delete_tag.rs
Normal file
14
src/discord/commands/delete_tag.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
use serenity::{builder::CreateApplicationCommand, model::prelude::command::CommandOptionType};
|
||||||
|
|
||||||
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||||
|
command
|
||||||
|
.name("delete_tag")
|
||||||
|
.description("Delete a tag")
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("tag")
|
||||||
|
.description("The tag to delete")
|
||||||
|
.kind(CommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
}
|
5
src/discord/commands/list_tags.rs
Normal file
5
src/discord/commands/list_tags.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use serenity::builder::CreateApplicationCommand;
|
||||||
|
|
||||||
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||||
|
command.name("list_tags").description("List your own tags")
|
||||||
|
}
|
17
src/discord/commands/source_code.rs
Normal file
17
src/discord/commands/source_code.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use serenity::builder::{CreateApplicationCommand, CreateInteractionResponseData};
|
||||||
|
|
||||||
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||||
|
command
|
||||||
|
.name("source_code")
|
||||||
|
.description("Access to the bot source code")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run<'a, 'b>(
|
||||||
|
response: &'a mut CreateInteractionResponseData<'b>,
|
||||||
|
) -> &'a mut CreateInteractionResponseData<'b> {
|
||||||
|
response.embed(|embed| {
|
||||||
|
embed
|
||||||
|
.title("Yorokobot repository")
|
||||||
|
.description("https://sr.ht/~victormignot/yorokobot/")
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,87 +1,69 @@
|
||||||
|
use crate::database::Client as DatabaseClient;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
model::gateway::Ready,
|
model::gateway::Ready,
|
||||||
model::{
|
model::{
|
||||||
application::command::{Command, CommandOptionType},
|
application::command::Command,
|
||||||
prelude::ResumedEvent,
|
prelude::{
|
||||||
|
interaction::{Interaction, InteractionResponseType},
|
||||||
|
ResumedEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
prelude::{Context, EventHandler},
|
prelude::{Context, EventHandler},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::database::Client as DatabaseClient;
|
use super::commands::*;
|
||||||
|
|
||||||
const MAX_ARGS_NUMBER: u32 = 25;
|
const MAX_ARGS_NUMBER: u32 = 25;
|
||||||
|
|
||||||
pub struct Handler<'a> {
|
pub struct Handler {
|
||||||
pub database: &'a DatabaseClient,
|
pub database: DatabaseClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventHandler for Handler<'_> {
|
impl EventHandler for Handler {
|
||||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||||
println!("Successfully connected as {}", ready.user.name);
|
println!("Successfully connected as {}", ready.user.name);
|
||||||
|
|
||||||
match Command::create_global_application_command(&ctx.http, |command| {
|
match Command::set_global_application_commands(&ctx.http, |commands| {
|
||||||
command
|
commands
|
||||||
.name("create_tag")
|
.create_application_command(|command| source_code::register(command))
|
||||||
.description("Add a new tag")
|
.create_application_command(|command| create_tag::register(command))
|
||||||
.create_option(|option| {
|
.create_application_command(|command| {
|
||||||
option
|
bulk_create_tag::register(command, MAX_ARGS_NUMBER)
|
||||||
.name("tag")
|
|
||||||
.description("The tag to create")
|
|
||||||
.kind(CommandOptionType::String)
|
|
||||||
.required(true)
|
|
||||||
})
|
})
|
||||||
|
.create_application_command(|command| delete_tag::register(command))
|
||||||
|
.create_application_command(|command| list_tags::register(command))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => println!("Successfully registered create_tag command"),
|
Ok(_) => println!("Successfully registered application commands"),
|
||||||
Err(e) => println!("Failed to register create_tag command : {e}"),
|
Err(e) => println!("Failed to register application commands: {e}"),
|
||||||
};
|
|
||||||
|
|
||||||
match Command::create_global_application_command(&ctx.http, |command| {
|
|
||||||
let command = command
|
|
||||||
.name("bulk_create_tag")
|
|
||||||
.description("Add multiples tags");
|
|
||||||
|
|
||||||
for i in 0..MAX_ARGS_NUMBER {
|
|
||||||
command.create_option(|option| {
|
|
||||||
option
|
|
||||||
.name(format!("tag{}", i + 1))
|
|
||||||
.description("A new tag to add")
|
|
||||||
.kind(CommandOptionType::String)
|
|
||||||
.required(i == 0)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
command
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => println!("Successfully registered bulk_create_tag command"),
|
|
||||||
Err(e) => println!("Failed to register bulk_create_tag command: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
match Command::create_global_application_command(&ctx.http, |command| {
|
|
||||||
command
|
|
||||||
.name("delete_tag")
|
|
||||||
.description("Delete a tag")
|
|
||||||
.create_option(|option| {
|
|
||||||
option
|
|
||||||
.name("tag")
|
|
||||||
.description("The tag to delete")
|
|
||||||
.kind(CommandOptionType::String)
|
|
||||||
.required(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => println!("Successfully registered delete_tag command"),
|
|
||||||
Err(e) => println!("Failed to register delete_tag command: {e}"),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn resume(&self, _: Context, _: ResumedEvent) {
|
async fn resume(&self, _: Context, _: ResumedEvent) {
|
||||||
println!("Successfully reconnected.")
|
println!("Successfully reconnected.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||||
|
if let Interaction::ApplicationCommand(command) = interaction {
|
||||||
|
println!("Received command {}", command.data.name);
|
||||||
|
|
||||||
|
if let Err(e) = command
|
||||||
|
.create_interaction_response(&ctx.http, |response| {
|
||||||
|
response
|
||||||
|
.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|message| match command.data.name.as_str() {
|
||||||
|
"source_code" => source_code::run(message),
|
||||||
|
"create_tag" => create_tag::run(message, &command, &self.database),
|
||||||
|
_ => message.content("Not yet implemented"),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
println!("Failed to answer to command: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue