feat: Mise en place server_config et debut de concour
This commit is contained in:
parent
c8cc1dd39a
commit
f043c99a4d
13
README.md
13
README.md
@ -8,7 +8,9 @@ Main lib used : [serenity-rs/serenity](https://github.com/serenity-rs/serenity)
|
||||
|
||||
## Feature expected
|
||||
|
||||
- ImageWareHouse (like TestDiscord)
|
||||
- [DONE] ImageWareHouse (like TestDiscord)
|
||||
- ImageWareHouse V2
|
||||
- Mise en place d'autre source de gif OPT
|
||||
- SoundBoard (like UnlabeledBot)
|
||||
- Notification (read an event topic and send the message to the expected chan)
|
||||
- Some Administration command
|
||||
@ -20,13 +22,12 @@ Main lib used : [serenity-rs/serenity](https://github.com/serenity-rs/serenity)
|
||||
- Have a web interface to manage the bot (like a dashboard)
|
||||
- List of server
|
||||
- Monitor the bot
|
||||
- Integrate with the Opentelemetry project
|
||||
- Authentification Discord
|
||||
- Detecter controle
|
||||
- [WIP] Integrate with the Opentelemetry project
|
||||
- The bot has to be able to be deployed on a k8s cluster
|
||||
- The bot has to be OPT-IN (the user has to enable the bot on his server with a command)
|
||||
|
||||
## Important to do
|
||||
|
||||
- Migrate to Trace
|
||||
- Mise en place de metric OpenTelemetry
|
||||
|
||||
## previous project
|
||||
|
||||
|
0
src/botv2/cmd/concour/mod.rs
Normal file
0
src/botv2/cmd/concour/mod.rs
Normal file
@ -1,10 +1,10 @@
|
||||
use crate::botv2::init::{Context, Error};
|
||||
use poise::samples::HelpConfiguration;
|
||||
use tracing::instrument;
|
||||
use crate::botv2::init::{Context,Error};
|
||||
|
||||
/// Show help message
|
||||
#[poise::command(prefix_command, track_edits, category = "Utility")]
|
||||
#[instrument(skip(ctx),level="info")]
|
||||
#[instrument(skip(ctx), level = "info")]
|
||||
pub async fn help(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Command to get help for"]
|
||||
@ -22,7 +22,7 @@ pub async fn help(
|
||||
};
|
||||
}
|
||||
let extra_text_at_bottom = "\
|
||||
Provided by Batleforc with love ❤️ and too much coffee ☕";
|
||||
Provided by Batleforc with ❤️ and too much ☕";
|
||||
|
||||
let config = HelpConfiguration {
|
||||
show_subcommands: true,
|
||||
|
@ -5,6 +5,7 @@ use crate::botv2::{
|
||||
use poise::CreateReply;
|
||||
use tracing::instrument;
|
||||
|
||||
/// Answer keyword with a meme if it match a registered keyword
|
||||
#[instrument(skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))]
|
||||
#[poise::command(slash_command, prefix_command, category = "meme")]
|
||||
pub async fn answer(
|
||||
|
@ -1,3 +1,5 @@
|
||||
pub mod ping;
|
||||
pub mod concour;
|
||||
pub mod help;
|
||||
pub mod meme;
|
||||
pub mod ping;
|
||||
pub mod server_config;
|
||||
|
81
src/botv2/cmd/server_config/feature.rs
Normal file
81
src/botv2/cmd/server_config/feature.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use crate::botv2::{
|
||||
domain::server_config::change_enable_server::change_enable_server,
|
||||
init::{Context, Error},
|
||||
};
|
||||
use poise::{
|
||||
serenity_prelude::{model::colour, CreateEmbed, CreateEmbedFooter},
|
||||
CreateReply,
|
||||
};
|
||||
use tracing::instrument;
|
||||
|
||||
/// Enable/Disable feature
|
||||
#[instrument(skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))]
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
category = "server_config",
|
||||
guild_only = true
|
||||
)]
|
||||
pub async fn feature(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Enable/Disable the auto_meme feature"] auto_meme: Option<bool>,
|
||||
#[description = "Enable/Disable the concour feature"] concour: Option<bool>,
|
||||
) -> Result<(), Error> {
|
||||
let guild = match ctx.guild_id() {
|
||||
Some(guild) => guild,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let entity_name = ctx.data().entity_name.clone();
|
||||
let footer = CreateEmbedFooter::new(entity_name.clone());
|
||||
let answer_auto_meme = match auto_meme {
|
||||
Some(enable) => match change_enable_server(guild.get(), enable).await {
|
||||
Ok(_) => Some(
|
||||
CreateEmbed::new()
|
||||
.title(format!("Auto meme feature initialized: {}", enable))
|
||||
.color(colour::Color::DARK_GREEN),
|
||||
),
|
||||
Err(_) => Some(
|
||||
CreateEmbed::new()
|
||||
.title("Error initializing auto meme feature")
|
||||
.color(colour::Color::RED),
|
||||
),
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
let answer_enable_concour = match concour {
|
||||
Some(enable) => match change_enable_server(guild.get(), enable).await {
|
||||
Ok(_) => Some(
|
||||
CreateEmbed::new()
|
||||
.title(format!("Concour feature initialized: {}", enable))
|
||||
.color(colour::Color::DARK_GREEN),
|
||||
),
|
||||
Err(_) => Some(
|
||||
CreateEmbed::new()
|
||||
.title("Error initializing concour feature")
|
||||
.color(colour::Color::RED),
|
||||
),
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut builder = CreateReply::default().ephemeral(true);
|
||||
if answer_auto_meme.is_none() && answer_enable_concour.is_none() {
|
||||
builder = builder.embed(
|
||||
CreateEmbed::new()
|
||||
.title("No feature initialized")
|
||||
.color(colour::Color::RED)
|
||||
.footer(footer.clone()),
|
||||
);
|
||||
}
|
||||
if let Some(embed) = answer_auto_meme {
|
||||
builder = builder.embed(embed.footer(footer.clone()));
|
||||
}
|
||||
if let Some(embed) = answer_enable_concour {
|
||||
builder = builder.embed(embed.footer(footer));
|
||||
}
|
||||
|
||||
if let Err(why) = ctx.send(builder).await {
|
||||
tracing::error!("Error sending message: {:?}", why);
|
||||
}
|
||||
Ok(())
|
||||
}
|
46
src/botv2/cmd/server_config/init_server.rs
Normal file
46
src/botv2/cmd/server_config/init_server.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use crate::botv2::{
|
||||
domain::server_config::change_enable_server::change_enable_server,
|
||||
init::{Context, Error},
|
||||
};
|
||||
use poise::{
|
||||
serenity_prelude::{model::colour, CreateEmbed, CreateEmbedFooter},
|
||||
CreateReply,
|
||||
};
|
||||
use tracing::instrument;
|
||||
|
||||
/// Initialize server config
|
||||
#[instrument(skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))]
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
category = "server_config",
|
||||
guild_only = true,
|
||||
owners_only = true
|
||||
)]
|
||||
pub async fn init(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Enable the bot to answer to the server"] enable: bool,
|
||||
) -> Result<(), Error> {
|
||||
let guild = match ctx.guild_id() {
|
||||
Some(guild) => guild,
|
||||
None => return Ok(()),
|
||||
};
|
||||
ctx.author_member().await.unwrap();
|
||||
let entity_name = ctx.data().entity_name.clone();
|
||||
let footer = CreateEmbedFooter::new(entity_name.clone());
|
||||
let answer = match change_enable_server(guild.get(), enable).await {
|
||||
Ok(_) => CreateEmbed::new()
|
||||
.title("Server config initialized")
|
||||
.color(colour::Color::DARK_GREEN),
|
||||
Err(_) => CreateEmbed::new()
|
||||
.title("Error initializing server config")
|
||||
.color(colour::Color::RED),
|
||||
};
|
||||
let builder = CreateReply::default()
|
||||
.embed(answer.footer(footer))
|
||||
.ephemeral(true);
|
||||
if let Err(why) = ctx.send(builder).await {
|
||||
tracing::error!("Error sending message: {:?}", why);
|
||||
}
|
||||
Ok(())
|
||||
}
|
3
src/botv2/cmd/server_config/mod.rs
Normal file
3
src/botv2/cmd/server_config/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod feature;
|
||||
pub mod init_server;
|
||||
pub mod server;
|
104
src/botv2/cmd/server_config/server.rs
Normal file
104
src/botv2/cmd/server_config/server.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use crate::botv2::{
|
||||
cmd::server_config::{feature::feature, init_server::init},
|
||||
domain::server_config::get_server_config::get_server_config,
|
||||
init::{Context, Error},
|
||||
};
|
||||
use poise::{
|
||||
serenity_prelude::{model::colour, CreateEmbed, CreateEmbedFooter, RoleId},
|
||||
CreateReply,
|
||||
};
|
||||
use tracing::instrument;
|
||||
|
||||
/// Show server config (alias of info)
|
||||
#[instrument(skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))]
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
category = "server_config",
|
||||
subcommands("init", "info", "feature"),
|
||||
guild_only = true
|
||||
)]
|
||||
pub async fn server(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Reponse cacher ?"] ephemeral: Option<bool>,
|
||||
) -> Result<(), Error> {
|
||||
server_info(ctx, ephemeral).await
|
||||
}
|
||||
|
||||
/// Show server config
|
||||
#[instrument(skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))]
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
category = "server_config",
|
||||
guild_only = true
|
||||
)]
|
||||
pub async fn info(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Reponse cacher ?"] ephemeral: Option<bool>,
|
||||
) -> Result<(), Error> {
|
||||
server_info(ctx, ephemeral).await
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx), level = "info")]
|
||||
async fn server_info(ctx: Context<'_>, ephemeral: Option<bool>) -> Result<(), Error> {
|
||||
let guild = match ctx.guild_id() {
|
||||
Some(guild) => guild,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let entity_name = ctx.data().entity_name.clone();
|
||||
let footer = CreateEmbedFooter::new(entity_name.clone());
|
||||
let answer = match get_server_config(guild.get()).await {
|
||||
Ok(config) => match config {
|
||||
Some(server_config) => {
|
||||
let mut embed = CreateEmbed::new()
|
||||
.title(format!(
|
||||
"Server config found: {}",
|
||||
ctx.guild().unwrap().name
|
||||
))
|
||||
.field("Enabled", server_config.enable.to_string(), true)
|
||||
.field(
|
||||
"Feature Auto_meme",
|
||||
server_config.auto_meme.to_string(),
|
||||
true,
|
||||
)
|
||||
.field(
|
||||
"Feature Concour",
|
||||
server_config.auto_concour.to_string(),
|
||||
true,
|
||||
)
|
||||
.color(colour::Color::DARK_GREEN);
|
||||
|
||||
let role_list: Vec<String> = server_config
|
||||
.admin_role
|
||||
.iter()
|
||||
.map(|role_id| {
|
||||
ctx.guild().unwrap().roles[&RoleId::new(*role_id)]
|
||||
.name
|
||||
.clone()
|
||||
})
|
||||
.collect();
|
||||
if !role_list.is_empty() {
|
||||
embed = embed.field("Admin role", role_list.join(", "), false);
|
||||
} else {
|
||||
embed = embed.field("Admin role", "No role found", false);
|
||||
}
|
||||
embed
|
||||
}
|
||||
None => CreateEmbed::new()
|
||||
.title("Server config not found")
|
||||
.color(colour::Color::RED),
|
||||
},
|
||||
Err(_) => CreateEmbed::new()
|
||||
.title("Error fetching server config")
|
||||
.color(colour::Color::RED),
|
||||
};
|
||||
let mut builder = CreateReply::default().embed(answer.footer(footer));
|
||||
if ephemeral.unwrap_or(true) {
|
||||
builder = builder.ephemeral(true);
|
||||
}
|
||||
if let Err(why) = ctx.send(builder).await {
|
||||
tracing::error!("Error sending message: {:?}", why);
|
||||
}
|
||||
Ok(())
|
||||
}
|
57
src/botv2/domain/concour/check_if_allowed.rs
Normal file
57
src/botv2/domain/concour/check_if_allowed.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use poise::serenity_prelude;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::{
|
||||
botv2::domain::server_config::{
|
||||
check_if_server_enable::check_if_server_enable,
|
||||
check_if_server_enable_and_admin::check_if_server_enable_and_user_admin,
|
||||
},
|
||||
db::server_config::ServerConfig,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum CheckIfConcourEnable {
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
// Check :
|
||||
// - if the user is admin or owner of the server
|
||||
// - if the server enabled the concour feature
|
||||
// - if the user has a role allowed to handle concour
|
||||
|
||||
/// Check if the concour is allowed on the server
|
||||
#[instrument(level = "info")]
|
||||
pub async fn check_if_concour_allowed(
|
||||
server_id: u64,
|
||||
) -> Result<(bool, Option<ServerConfig>), CheckIfConcourEnable> {
|
||||
if let Ok((enable, server_config)) = check_if_server_enable(server_id).await {
|
||||
if !enable {
|
||||
return Ok((false, None));
|
||||
}
|
||||
if let Some(server_config) = server_config {
|
||||
return Ok((server_config.auto_concour, Some(server_config)));
|
||||
}
|
||||
}
|
||||
Ok((false, None))
|
||||
}
|
||||
|
||||
/// Check if the concour is allowed on the server and if the user has a role allowed to handle concour
|
||||
#[instrument(level = "info", skip(http))]
|
||||
pub async fn check_if_allowed(
|
||||
server_id: u64,
|
||||
user_id: u64,
|
||||
http: serenity_prelude::Http,
|
||||
) -> Result<bool, CheckIfConcourEnable> {
|
||||
if let Ok((enable, server_config)) =
|
||||
check_if_server_enable_and_user_admin(server_id, user_id, http).await
|
||||
{
|
||||
if !enable {
|
||||
return Ok(false);
|
||||
}
|
||||
if let Some(server_config) = server_config {
|
||||
return Ok(server_config.auto_concour);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
29
src/botv2/domain/concour/list_concour.rs
Normal file
29
src/botv2/domain/concour/list_concour.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{info, instrument};
|
||||
|
||||
use crate::db::concour::Concour;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum ListConcourError {
|
||||
FindError(String),
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
#[instrument(level = "info")]
|
||||
pub async fn list_concour(server_id: u64) -> Result<Vec<Concour>, ListConcourError> {
|
||||
let list_concour = match Concour::find_by_server_id(&server_id).await {
|
||||
Ok(list_concour) => list_concour,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error finding concour");
|
||||
return Err(ListConcourError::UnknownError(
|
||||
"Error finding concour".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
if list_concour.is_empty() {
|
||||
info!("No concour found");
|
||||
return Err(ListConcourError::FindError("No concour found".to_string()));
|
||||
}
|
||||
|
||||
Ok(list_concour)
|
||||
}
|
2
src/botv2/domain/concour/mod.rs
Normal file
2
src/botv2/domain/concour/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod check_if_allowed;
|
||||
pub mod list_concour;
|
53
src/botv2/domain/concour/readme.md
Normal file
53
src/botv2/domain/concour/readme.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Concour
|
||||
|
||||
## Kind Popularity
|
||||
|
||||
- Titre
|
||||
- Théme
|
||||
- Date debut/fin
|
||||
- Récompense
|
||||
- Manuelle
|
||||
- Automatique
|
||||
- Role
|
||||
- Message personalisé contenant ce que tu veux
|
||||
|
||||
### Déclarer un concour de popularité
|
||||
|
||||
1. Creer un channel
|
||||
2. Préparer la récompense
|
||||
3. Creer et configuré le concours de popularité dans le channel cible
|
||||
1. Creer : /concours-create kind:(string) title:(string) description:(string) fin:(date) (retourne l'id du concours)
|
||||
2. Changer les info : /concours-edit id:(object-id) banniere:(opt,string-url) title:(opt,string) description:(opt,string) fin:(date)
|
||||
3. Annoncer le concours : /concours-promo id:(object-id)
|
||||
4. Definir la récompense : /concours-set-recompense id:(object-id) kind:(string) content:(string,opt)
|
||||
5. Definir le channel : /concours-set-channel id:(object-id) channel-id:(u64)
|
||||
6. Cloturer le concours : /concours-end id:(object-id) fin:(date,opt)
|
||||
7. Annoncer le vainqueur : /concours-win id:(object-id) (si non finis, cloture le concours immédiatement)
|
||||
|
||||
### Sélectionner un vainqueur ?
|
||||
|
||||
Toute personne qui aura le plus d'émoji sur un message contenant une image
|
||||
|
||||
## Kind Automated Popularity
|
||||
|
||||
- Titre => String
|
||||
- Description => String
|
||||
- Date début => Date
|
||||
- Periode (1 Semaine ?) => Duration
|
||||
- CurrentWinner => Option<u64>
|
||||
- RoleRécompense => u64
|
||||
- KeyWordList => Vec<String>
|
||||
- Banniére => Option<String>
|
||||
- CurrentKeyWord => String
|
||||
- Status => Enum<Created,Paused,OnGoing,Finished>
|
||||
- HistoriqueWinner => HashMap<String,Option<(u64,Date)>>
|
||||
|
||||
### Command
|
||||
|
||||
- Creation /concours-create kind:(string) title:(string) description:(string) periode:(date)
|
||||
- Start /concours-start
|
||||
- List concours /concours-list
|
||||
|
||||
## Kind Check-in
|
||||
|
||||
Bot de concours avec participation reaction emoji
|
@ -1 +1,3 @@
|
||||
pub mod concour;
|
||||
pub mod meme;
|
||||
pub mod server_config;
|
||||
|
60
src/botv2/domain/server_config/change_enable_server.rs
Normal file
60
src/botv2/domain/server_config/change_enable_server.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::db::server_config::ServerConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum ChangeEnableServerError {
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
#[instrument(level = "info")]
|
||||
pub async fn change_enable_server(
|
||||
server_id: u64,
|
||||
enable: bool,
|
||||
) -> Result<(), ChangeEnableServerError> {
|
||||
let server_config =
|
||||
match crate::db::server_config::ServerConfig::find_by_server_id(&server_id).await {
|
||||
Ok(server_config) => server_config,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error finding server config");
|
||||
return Err(ChangeEnableServerError::UnknownError(
|
||||
"Error finding server config".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
match server_config {
|
||||
None => {
|
||||
tracing::info!("Server config not found, creating one");
|
||||
let mut server_config = ServerConfig::new(server_id).unwrap();
|
||||
server_config.enable = enable;
|
||||
match server_config.create().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error creating server config");
|
||||
return Err(ChangeEnableServerError::UnknownError(
|
||||
"Error creating server config".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(mut server_config) => {
|
||||
if server_config.enable == enable {
|
||||
tracing::info!("Server config already enabled/disabled");
|
||||
return Ok(());
|
||||
} else {
|
||||
tracing::info!("Updating server config");
|
||||
server_config.enable = enable;
|
||||
match server_config.update().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error updating server config");
|
||||
return Err(ChangeEnableServerError::UnknownError(
|
||||
"Error updating server config".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
src/botv2/domain/server_config/check_if_server_enable.rs
Normal file
32
src/botv2/domain/server_config/check_if_server_enable.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::db::server_config::ServerConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum CheckIfServerEnableError {
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
#[instrument(level = "info")]
|
||||
pub async fn check_if_server_enable(
|
||||
server_id: u64,
|
||||
) -> Result<(bool, Option<ServerConfig>), CheckIfServerEnableError> {
|
||||
let server_config =
|
||||
match crate::db::server_config::ServerConfig::find_by_server_id(&server_id).await {
|
||||
Ok(server_config) => server_config,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error finding server config");
|
||||
return Err(CheckIfServerEnableError::UnknownError(
|
||||
"Error finding server config".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
match server_config {
|
||||
None => {
|
||||
tracing::info!("Server config not found");
|
||||
return Ok((false, None));
|
||||
}
|
||||
Some(server_config) => Ok((server_config.enable, Some(server_config))),
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
use super::check_if_server_enable::{check_if_server_enable, CheckIfServerEnableError};
|
||||
use crate::db::server_config::ServerConfig;
|
||||
use poise::serenity_prelude::{self, RoleId, UserId};
|
||||
use tracing::instrument;
|
||||
|
||||
#[instrument(level = "info", skip(http))]
|
||||
pub async fn check_if_server_enable_and_user_admin(
|
||||
server_id: u64,
|
||||
user_id: u64,
|
||||
http: serenity_prelude::Http,
|
||||
) -> Result<(bool, Option<ServerConfig>), CheckIfServerEnableError> {
|
||||
let server_config = match check_if_server_enable(server_id).await {
|
||||
Ok((status, config)) => {
|
||||
if !status {
|
||||
return Ok((false, None));
|
||||
}
|
||||
config.unwrap()
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let guild = match http.get_guild(server_id.into()).await {
|
||||
Ok(guild) => guild,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error getting guild");
|
||||
return Err(CheckIfServerEnableError::UnknownError(
|
||||
"Error getting guild".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
if guild.owner_id.get() == user_id {
|
||||
return Ok((true, Some(server_config)));
|
||||
}
|
||||
match guild.member(http, UserId::new(user_id)).await {
|
||||
Ok(member) => Ok((
|
||||
server_config
|
||||
.clone()
|
||||
.admin_role
|
||||
.into_iter()
|
||||
.any(|role_id| member.roles.contains(&RoleId::new(role_id))),
|
||||
Some(server_config),
|
||||
)),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error getting member");
|
||||
return Err(CheckIfServerEnableError::UnknownError(
|
||||
"Error getting member".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
58
src/botv2/domain/server_config/enable_feature_auto_meme.rs
Normal file
58
src/botv2/domain/server_config/enable_feature_auto_meme.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::db::server_config::ServerConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum EnableFeatureMemeError {
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
#[instrument(level = "info")]
|
||||
pub async fn enable_feature_meme(
|
||||
server_id: u64,
|
||||
enable: bool,
|
||||
) -> Result<(), EnableFeatureMemeError> {
|
||||
let server_config =
|
||||
match crate::db::server_config::ServerConfig::find_by_server_id(&server_id).await {
|
||||
Ok(server_config) => server_config,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error finding server config");
|
||||
return Err(EnableFeatureMemeError::UnknownError(
|
||||
"Error finding server config".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
match server_config {
|
||||
None => {
|
||||
tracing::info!("Server config not found, creating it");
|
||||
let mut server_config = ServerConfig::new(server_id).unwrap();
|
||||
server_config.auto_meme = enable;
|
||||
match server_config.create().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error creating server config");
|
||||
return Err(EnableFeatureMemeError::UnknownError(
|
||||
"Error creating server config".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(mut server_config) => {
|
||||
if server_config.auto_meme == enable {
|
||||
return Ok(());
|
||||
} else {
|
||||
server_config.auto_meme = enable;
|
||||
match server_config.update().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error updating server config");
|
||||
return Err(EnableFeatureMemeError::UnknownError(
|
||||
"Error updating server config".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
src/botv2/domain/server_config/enable_feature_concour.rs
Normal file
58
src/botv2/domain/server_config/enable_feature_concour.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::db::server_config::ServerConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum EnableFeatureConcourError {
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
#[instrument(level = "info")]
|
||||
pub async fn enable_feature_concour(
|
||||
server_id: u64,
|
||||
enable: bool,
|
||||
) -> Result<(), EnableFeatureConcourError> {
|
||||
let server_config =
|
||||
match crate::db::server_config::ServerConfig::find_by_server_id(&server_id).await {
|
||||
Ok(server_config) => server_config,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error finding server config");
|
||||
return Err(EnableFeatureConcourError::UnknownError(
|
||||
"Error finding server config".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
match server_config {
|
||||
None => {
|
||||
tracing::info!("Server config not found, creating it");
|
||||
let mut server_config = ServerConfig::new(server_id).unwrap();
|
||||
server_config.auto_concour = enable;
|
||||
match server_config.create().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error creating server config");
|
||||
return Err(EnableFeatureConcourError::UnknownError(
|
||||
"Error creating server config".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(mut server_config) => {
|
||||
if server_config.auto_concour == enable {
|
||||
return Ok(());
|
||||
} else {
|
||||
server_config.auto_concour = enable;
|
||||
match server_config.update().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error updating server config");
|
||||
return Err(EnableFeatureConcourError::UnknownError(
|
||||
"Error updating server config".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
src/botv2/domain/server_config/get_server_config.rs
Normal file
26
src/botv2/domain/server_config/get_server_config.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::db::server_config::ServerConfig;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum GetServerConfigError {
|
||||
UnknownError(String),
|
||||
}
|
||||
|
||||
#[instrument(level = "info")]
|
||||
pub async fn get_server_config(
|
||||
server_id: u64,
|
||||
) -> Result<Option<ServerConfig>, GetServerConfigError> {
|
||||
let server_config =
|
||||
match crate::db::server_config::ServerConfig::find_by_server_id(&server_id).await {
|
||||
Ok(server_config) => server_config,
|
||||
Err(err) => {
|
||||
tracing::error!(error = err.to_string(), "Error finding server config");
|
||||
return Err(GetServerConfigError::UnknownError(
|
||||
"Error finding server config".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
Ok(server_config)
|
||||
}
|
6
src/botv2/domain/server_config/mod.rs
Normal file
6
src/botv2/domain/server_config/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub mod change_enable_server;
|
||||
pub mod check_if_server_enable;
|
||||
pub mod check_if_server_enable_and_admin;
|
||||
pub mod enable_feature_auto_meme;
|
||||
pub mod enable_feature_concour;
|
||||
pub mod get_server_config;
|
@ -1,4 +1,5 @@
|
||||
use crate::botv2::cmd::meme::{answer::answer, enable::enable, list::list};
|
||||
use crate::botv2::cmd::server_config::server::server;
|
||||
use crate::botv2::cmd::{help::help, ping::ping};
|
||||
use crate::config::Config;
|
||||
use crate::{botv2::handler::event_handler, img::config_file::ConfigFile};
|
||||
@ -58,7 +59,7 @@ pub async fn start_bot(config: Config, rx: oneshot::Receiver<()>) -> Arc<Http> {
|
||||
let prefix = config.prefix.clone();
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
commands: vec![age(), ping(), help(), list(), enable(), answer()],
|
||||
commands: vec![age(), ping(), help(), list(), enable(), answer(), server()],
|
||||
prefix_options: poise::PrefixFrameworkOptions {
|
||||
prefix: Some(prefix.into()),
|
||||
..Default::default()
|
||||
|
121
src/db/concour.rs
Normal file
121
src/db/concour.rs
Normal file
@ -0,0 +1,121 @@
|
||||
use super::init::DB;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use surrealdb::opt::Resource;
|
||||
|
||||
const CONCOUR: &str = "concour";
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum ConcourStatus {
|
||||
Created,
|
||||
Paused,
|
||||
OnGoing,
|
||||
Finished,
|
||||
}
|
||||
|
||||
impl fmt::Display for ConcourStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Concour {
|
||||
pub server_id: u64,
|
||||
pub enable: bool,
|
||||
pub channel_id: u64,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub start_date: chrono::DateTime<chrono::Utc>,
|
||||
pub periode: time::Duration,
|
||||
pub role_récompense: u64,
|
||||
pub keywords: Vec<String>,
|
||||
pub banner: Option<String>,
|
||||
pub index_keyword: u64,
|
||||
pub status: ConcourStatus,
|
||||
pub winner: HashMap<String, (u64, chrono::DateTime<chrono::Utc>)>,
|
||||
}
|
||||
|
||||
impl Concour {
|
||||
pub fn new(server_id: u64, channel_id: u64, enable: bool) -> Result<Self, surrealdb::Error> {
|
||||
Ok(Self {
|
||||
server_id,
|
||||
enable,
|
||||
channel_id,
|
||||
title: String::new(),
|
||||
description: String::new(),
|
||||
start_date: chrono::Utc::now(),
|
||||
periode: time::Duration::days(0),
|
||||
role_récompense: 0,
|
||||
keywords: Vec::new(),
|
||||
banner: None,
|
||||
index_keyword: 0,
|
||||
status: ConcourStatus::Created,
|
||||
winner: HashMap::new(),
|
||||
})
|
||||
}
|
||||
pub async fn create(&self) -> Result<(), surrealdb::Error> {
|
||||
match DB.create(Resource::from(CONCOUR)).content(&self).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
pub async fn update(&self) -> Result<(), surrealdb::Error> {
|
||||
let sql = format!(
|
||||
"UPDATE {} SET enable = {}, title = '{}', description = '{}', start_date = '{}', periode = '{}', role_récompense = {}, keywords = '{:?}', banner = '{:?}', index_keyword = {}, status = '{}', winner = '{:?}' WHERE server_id = {} and channel_id = {}",
|
||||
CONCOUR, self.enable, self.title, self.description, self.start_date, self.periode, self.role_récompense, self.keywords, self.banner, self.index_keyword, self.status, self.winner, self.server_id, self.channel_id
|
||||
);
|
||||
match DB.query(sql).await {
|
||||
Ok(res) => {
|
||||
println!("{:?}", res);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
pub async fn find_by_server_id_channel_id(
|
||||
server_id: &u64,
|
||||
channel_id: &u64,
|
||||
) -> Result<Option<Concour>, surrealdb::Error> {
|
||||
let sql = format!(
|
||||
"SELECT * FROM {} WHERE server_id = {} AND channel_id = {}",
|
||||
CONCOUR, server_id, channel_id
|
||||
);
|
||||
let mut results = match DB.query(&sql).await {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let concour: Concour = match results.take(0) {
|
||||
Ok(Some(concour)) => concour,
|
||||
Ok(None) => {
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
Ok(Some(concour))
|
||||
}
|
||||
pub async fn find_by_server_id(server_id: &u64) -> Result<Vec<Concour>, surrealdb::Error> {
|
||||
let sql = format!("SELECT * FROM {} WHERE server_id = {}", CONCOUR, server_id);
|
||||
let mut results = match DB.query(&sql).await {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let mut concours = Vec::new();
|
||||
while let Ok(Some(concour)) = results.take(0) {
|
||||
concours.push(concour);
|
||||
}
|
||||
Ok(concours)
|
||||
}
|
||||
}
|
@ -1,2 +1,4 @@
|
||||
pub mod user_image;
|
||||
pub mod concour;
|
||||
pub mod init;
|
||||
pub mod server_config;
|
||||
pub mod user_image;
|
||||
|
89
src/db/server_config.rs
Normal file
89
src/db/server_config.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use super::init::DB;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use surrealdb::opt::Resource;
|
||||
|
||||
const SERVER_CONFIG: &str = "server_config";
|
||||
const fn default_false() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ServerConfig {
|
||||
#[serde(default = "default_false")]
|
||||
pub enable: bool,
|
||||
pub server_id: u64,
|
||||
#[serde(default = "default_false")]
|
||||
pub auto_meme: bool,
|
||||
#[serde(default = "default_false")]
|
||||
pub auto_concour: bool,
|
||||
pub admin_role: Vec<u64>,
|
||||
}
|
||||
|
||||
impl fmt::Display for ServerConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
pub fn new(server_id: u64) -> Result<Self, surrealdb::Error> {
|
||||
Ok(Self {
|
||||
enable: false,
|
||||
server_id,
|
||||
auto_meme: false,
|
||||
auto_concour: false,
|
||||
admin_role: Vec::new(),
|
||||
})
|
||||
}
|
||||
pub async fn create(&self) -> Result<(), surrealdb::Error> {
|
||||
match DB
|
||||
.create(Resource::from(SERVER_CONFIG))
|
||||
.content(&self)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub async fn update(&self) -> Result<(), surrealdb::Error> {
|
||||
let sql = format!(
|
||||
"UPDATE {} SET enable = {}, auto_meme = {}, auto_concour = {}, admin_role = '{:?}' WHERE server_id = {}",
|
||||
SERVER_CONFIG,
|
||||
self.enable,
|
||||
self.auto_meme,
|
||||
self.auto_concour,
|
||||
self.admin_role,
|
||||
self.server_id
|
||||
);
|
||||
match DB.query(&sql).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub async fn find_by_server_id(
|
||||
server_id: &u64,
|
||||
) -> Result<Option<ServerConfig>, surrealdb::Error> {
|
||||
let sql = format!(
|
||||
"SELECT * FROM {} WHERE server_id = {}",
|
||||
SERVER_CONFIG, server_id
|
||||
);
|
||||
let mut results = match DB.query(&sql).await {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let server_config: ServerConfig = match results.take(0) {
|
||||
Ok(Some(server_config)) => server_config,
|
||||
Ok(None) => {
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(server_config))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user