diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 6b37cb7..91cb0be 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,4 +1,5 @@ -use anyhow::Result; +use std::sync::atomic::{AtomicU64, Ordering}; + use serenity::all::{CommandInteraction, Context, CreateCommand}; use sqlx::PgPool; @@ -10,7 +11,6 @@ include!("./mod_gen.rs"); pub enum CommandCategory { Moderation, Utils, - Gestion, } impl CommandCategory { @@ -18,7 +18,6 @@ impl CommandCategory { match self { Self::Utils => "🌐", Self::Moderation => "🛡️", - Self::Gestion => "👑", } } @@ -26,7 +25,6 @@ impl CommandCategory { match self { Self::Utils => "Utils", Self::Moderation => "Moderation", - Self::Gestion => "Gestion", } } } @@ -36,6 +34,15 @@ pub trait SlashCommand: Send + Sync { fn name(&self) -> &'static str; fn description(&self) -> &'static str; fn category(&self) -> &'static CommandCategory; + fn command_id_ref(&self) -> &AtomicU64; + + fn get_id(&self) -> u64 { + self.command_id_ref().load(Ordering::Relaxed) + } + + fn set_id(&self, id: u64) { + self.command_id_ref().store(id, Ordering::Relaxed); + } fn register(&self) -> CreateCommand; @@ -45,7 +52,7 @@ pub trait SlashCommand: Send + Sync { command: &CommandInteraction, database: &PgPool, _emoji: &EmojiConfig, - ) -> Result<()>; + ) -> Result<(), serenity::Error>; } pub struct CommandEntry { diff --git a/src/commands/utils/ping.rs b/src/commands/utils/ping.rs index 1c3cc86..1a5919e 100644 --- a/src/commands/utils/ping.rs +++ b/src/commands/utils/ping.rs @@ -1,4 +1,7 @@ use std::{ + sync::atomic::{ + AtomicU64, + }, time::Instant, }; @@ -14,10 +17,19 @@ use serenity::all::{ CreateInteractionResponseMessage, EditInteractionResponse, }; use sqlx::PgPool; -use tracing::{debug, info}; -use anyhow::Result; +use tracing::info; -pub struct Ping; +pub struct Ping { + pub command_id: AtomicU64, +} + +impl Ping { + pub fn new() -> Self { + Self { + command_id: AtomicU64::new(0), + } + } +} #[serenity::async_trait] impl SlashCommand for Ping { @@ -33,6 +45,10 @@ impl SlashCommand for Ping { &CommandCategory::Utils } + fn command_id_ref(&self) -> &AtomicU64 { + &self.command_id + } + fn register(&self) -> CreateCommand { info!("\t✅ | {}", self.name()); CreateCommand::new(self.name()).description(self.description()) @@ -44,8 +60,7 @@ impl SlashCommand for Ping { command: &CommandInteraction, _database: &PgPool, _emoji: &EmojiConfig, - ) -> Result<()> { - debug!("Ping command called"); + ) -> Result<(), serenity::Error> { let message: CreateInteractionResponseMessage = CreateInteractionResponseMessage::new() .content("🏓 | Pong!") .ephemeral(true); @@ -66,5 +81,5 @@ impl SlashCommand for Ping { } inventory::submit! { - CommandEntry { create: || Box::new(Ping) } + CommandEntry { create: || Box::new(Ping::new()) } } diff --git a/src/database/bot.rs b/src/database/bot.rs index c895ec3..5819933 100644 --- a/src/database/bot.rs +++ b/src/database/bot.rs @@ -1,17 +1,16 @@ use sqlx::{PgPool, query, query_as}; use crate::models::bot::{DbBot, BotPresence, BotActivity}; -use anyhow::Result; const BOT_ID: i32 = 1; -pub async fn init(db: &PgPool) -> Result<()> { +pub async fn init(db: &PgPool) -> Result<(), sqlx::Error> { query!("INSERT INTO bots (id) VALUES ($1) ON CONFLICT DO NOTHING", BOT_ID) .execute(db) .await?; Ok(()) } -pub async fn get(db: &PgPool) -> Result> { +pub async fn get(db: &PgPool) -> Result, sqlx::Error> { let bot: Option = query_as!( DbBot, r#"SELECT status, activity_type as "activity_type: BotActivity", presence as "presence: BotPresence" FROM bots WHERE id = $1"#, @@ -22,21 +21,21 @@ pub async fn get(db: &PgPool) -> Result> { Ok(bot) } -pub async fn set_status(db: &PgPool, status: &str) -> Result<()> { +pub async fn set_status(db: &PgPool, status: &str) -> Result<(), sqlx::Error> { query!("UPDATE bots SET status = $1 WHERE id = $2", status, BOT_ID) .execute(db) .await?; Ok(()) } -pub async fn set_activity(db: &PgPool, activity: BotActivity) -> Result<()> { +pub async fn set_activity(db: &PgPool, activity: BotActivity) -> Result<(), sqlx::Error> { query!("UPDATE bots SET activity_type = $1::bot_activity WHERE id = $2", activity as BotActivity, BOT_ID) .execute(db) .await?; Ok(()) } -pub async fn set_presence(db: &PgPool, presence: BotPresence) -> Result<()> { +pub async fn set_presence(db: &PgPool, presence: BotPresence) -> Result<(), sqlx::Error> { query!("UPDATE bots SET presence = $1::bot_presence WHERE id = $2", presence as BotPresence, BOT_ID) .execute(db) .await?; diff --git a/src/database/guild.rs b/src/database/guild.rs index 033f94c..0dd051d 100644 --- a/src/database/guild.rs +++ b/src/database/guild.rs @@ -5,7 +5,6 @@ use sqlx::{ query_scalar, }; use crate::models::DbGuild; -use anyhow::Result; pub enum LogChannel { Bot, @@ -49,21 +48,21 @@ fn protect_select(asked: Protect) -> &'static str { } } -pub async fn create(db: &PgPool, guild_id: &str) -> Result<()> { +pub async fn create(db: &PgPool, guild_id: &str) -> Result<(), sqlx::Error> { query!("INSERT INTO guilds (guild_id) VALUES ($1) ON CONFLICT DO NOTHING", guild_id) .execute(db) .await?; Ok(()) } -pub async fn delete(db: &PgPool, guild_id: &str) -> Result<()> { +pub async fn delete(db: &PgPool, guild_id: &str) -> Result<(), sqlx::Error> { query!("DELETE FROM guilds WHERE guild_id = $1", guild_id) .execute(db) .await?; Ok(()) } -pub async fn get(db: &PgPool, guild_id: &str) -> Result> { +pub async fn get(db: &PgPool, guild_id: &str) -> Result, sqlx::Error> { let guild: Option = query_as!( DbGuild, "SELECT * FROM guilds WHERE guild_id = $1", @@ -74,7 +73,7 @@ pub async fn get(db: &PgPool, guild_id: &str) -> Result> { Ok(guild) } -pub async fn get_log(db: &PgPool, guild_id: &str, asked: LogChannel) -> Result> { +pub async fn get_log(db: &PgPool, guild_id: &str, asked: LogChannel) -> Result, sqlx::Error> { let sql: String = format!("SELECT {} FROM guilds WHERE guild_id = $1", log_select(asked)); let channel_id: Option = query_scalar(&sql) .bind(guild_id) @@ -83,7 +82,7 @@ pub async fn get_log(db: &PgPool, guild_id: &str, asked: LogChannel) -> Result Result<()> { +pub async fn set_log(db: &PgPool, guild_id: &str, asked: LogChannel, value: &str) -> Result<(), sqlx::Error> { let sql: String = format!("UPDATE guilds set {} = $1 WHERE guild_id = $2", log_select(asked)); query(&sql) .bind(value) @@ -93,7 +92,7 @@ pub async fn set_log(db: &PgPool, guild_id: &str, asked: LogChannel, value: &str Ok(()) } -pub async fn get_protect(db: &PgPool, guild_id: &str, asked: Protect) -> Result> { +pub async fn get_protect(db: &PgPool, guild_id: &str, asked: Protect) -> Result, sqlx::Error> { let sql: String = format!("SELECT {} FROM guilds WHERE guild_id = $1", protect_select(asked)); let state: Option = query_scalar(&sql) .bind(guild_id) @@ -102,7 +101,7 @@ pub async fn get_protect(db: &PgPool, guild_id: &str, asked: Protect) -> Result< Ok(state) } -pub async fn set_protect(db: &PgPool, guild_id: &str, asked: Protect, value: &str) -> Result<()> { +pub async fn set_protect(db: &PgPool, guild_id: &str, asked: Protect, value: &str) -> Result<(), sqlx::Error> { let sql: String = format!("UPDATE guilds set {} = $1 WHERE guild_id = $2", protect_select(asked)); query(&sql) .bind(value) @@ -112,9 +111,9 @@ pub async fn set_protect(db: &PgPool, guild_id: &str, asked: Protect, value: &st Ok(()) } -pub async fn get_or_create(db: &PgPool, guild_id: &str) -> Result { +pub async fn get_or_create(db: &PgPool, guild_id: &str) -> Result { create(db, guild_id).await?; get(db, guild_id) .await? - .ok_or_else(|| sqlx::Error::RowNotFound.into()) + .ok_or_else(|| sqlx::Error::RowNotFound) } diff --git a/src/database/guild_user.rs b/src/database/guild_user.rs index afb9f14..b69c66b 100644 --- a/src/database/guild_user.rs +++ b/src/database/guild_user.rs @@ -1,12 +1,11 @@ use sqlx::{PgPool, query, query_as, query_scalar}; use crate::models::guild_user::DbGuildUser; -use anyhow::Result; pub async fn get( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result> { +) -> Result, sqlx::Error> { let guild_user = query_as!( DbGuildUser, "SELECT * FROM guild_users WHERE user_id = $1 AND guild_id = $2", @@ -22,7 +21,7 @@ pub async fn create( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "INSERT INTO guild_users (user_id, guild_id) \ VALUES ($1, $2) \ @@ -39,7 +38,7 @@ pub async fn delete( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "DELETE FROM guild_users WHERE user_id = $1 AND guild_id = $2", user_id, @@ -53,7 +52,7 @@ pub async fn delete( pub async fn delete_all_in_guild( db: &PgPool, guild_id: &str, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!("DELETE FROM guild_users WHERE guild_id = $1", guild_id) .execute(db) .await?; @@ -65,7 +64,7 @@ pub async fn add_xp( user_id: &str, guild_id: &str, amount: i32, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "UPDATE guild_users SET xp = xp + $1 \ WHERE user_id = $2 AND guild_id = $3", @@ -83,7 +82,7 @@ pub async fn set_level( user_id: &str, guild_id: &str, level: i32, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "UPDATE guild_users SET level = $1 \ WHERE user_id = $2 AND guild_id = $3", @@ -100,7 +99,7 @@ pub async fn get_xp( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result> { +) -> Result, sqlx::Error> { let xp: Option = query_scalar( "SELECT xp FROM guild_users WHERE user_id = $1 AND guild_id = $2", ) @@ -115,7 +114,7 @@ pub async fn get_level( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result> { +) -> Result, sqlx::Error> { let level: Option = query_scalar("SELECT level FROM guild_users WHERE user_id = $1 AND guild_id = $2") .bind(user_id) .bind(guild_id) @@ -129,7 +128,7 @@ pub async fn set_wl( user_id: &str, guild_id: &str, value: bool, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "UPDATE guild_users SET is_wl_user = $1 \ WHERE user_id = $2 AND guild_id = $3", @@ -145,7 +144,7 @@ pub async fn set_wl( pub async fn get_all_wl( db: &PgPool, guild_id: &str, -) -> Result> { +) -> Result, sqlx::Error> { let users = query_as!( DbGuildUser, "SELECT * FROM guild_users \ @@ -162,7 +161,7 @@ pub async fn set_invited_by( user_id: &str, guild_id: &str, inviter_id: &str, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "UPDATE guild_users SET invited_by = $1 \ WHERE user_id = $2 AND guild_id = $3", @@ -179,7 +178,7 @@ pub async fn increment_invitations( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "UPDATE guild_users SET invitation_count = invitation_count + 1 \ WHERE user_id = $1 AND guild_id = $2", @@ -195,7 +194,7 @@ pub async fn decrement_invitations( db: &PgPool, user_id: &str, guild_id: &str, -) -> Result<()> { +) -> Result<(), sqlx::Error> { query!( "UPDATE guild_users SET invitation_count = GREATEST(invitation_count - 1, 0) \ WHERE user_id = $1 AND guild_id = $2", @@ -211,7 +210,7 @@ pub async fn leaderboard_xp( db: &PgPool, guild_id: &str, limit: i64, -) -> Result> { +) -> Result, sqlx::Error> { let users = query_as!( DbGuildUser, "SELECT * FROM guild_users \ @@ -230,7 +229,7 @@ pub async fn leaderboard_invitations( db: &PgPool, guild_id: &str, limit: i64, -) -> Result> { +) -> Result, sqlx::Error> { let users = query_as!( DbGuildUser, "SELECT * FROM guild_users \ @@ -244,9 +243,9 @@ pub async fn leaderboard_invitations( .await?; Ok(users) } -pub async fn get_or_create(db: &PgPool, user_id: &str, guild_id: &str) -> Result { +pub async fn get_or_create(db: &PgPool, user_id: &str, guild_id: &str) -> Result { create(db, user_id, guild_id).await?; get(db, user_id, guild_id) .await? - .ok_or_else(|| sqlx::Error::RowNotFound.into()) + .ok_or_else(|| sqlx::Error::RowNotFound) } diff --git a/src/database/user.rs b/src/database/user.rs index d6873f3..20ffa16 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -4,7 +4,6 @@ use sqlx::{ query_as, }; use crate::models::DbUser; -use anyhow::Result; /// Adding the user (if exist do nothing) /// @@ -13,8 +12,8 @@ use anyhow::Result; /// /// # Errors /// -/// Returns `Error` if the query fails. -pub async fn create(db: &PgPool, user_id: &str) -> Result<()> { +/// Returns `sqlx::Error` if the query fails. +pub async fn create(db: &PgPool, user_id: &str) -> Result<(), sqlx::Error> { query!("INSERT INTO users (user_id) VALUES ($1) ON CONFLICT DO NOTHING", user_id) .execute(db) .await?; @@ -33,8 +32,8 @@ pub async fn create(db: &PgPool, user_id: &str) -> Result<()> { /// /// # Errors /// -/// Returns `Error` if the query fails. -pub async fn get(db: &PgPool, user_id: &str) -> Result> { +/// Returns `sqlx::Error` if the query fails. +pub async fn get(db: &PgPool, user_id: &str) -> Result, sqlx::Error> { let user: Option = query_as!( DbUser, "SELECT * FROM users WHERE user_id = $1", @@ -53,8 +52,8 @@ pub async fn get(db: &PgPool, user_id: &str) -> Result> { /// /// # Errors /// -/// Returns `Error` if the query fails. -pub async fn set_owner(db: &PgPool, user_id: &str, value: bool) -> Result<()> { +/// Returns `sqlx::Error` if the query fails. +pub async fn set_owner(db: &PgPool, user_id: &str, value: bool) -> Result<(), sqlx::Error> { query!("UPDATE users set is_owner = $1 WHERE user_id = $2", value, user_id) .execute(db) .await?; @@ -69,8 +68,8 @@ pub async fn set_owner(db: &PgPool, user_id: &str, value: bool) -> Result<()> { /// /// # Errors /// -/// Returns `Error` if the query fails. -pub async fn set_buyer(db: &PgPool, user_id: &str, value: bool) -> Result<()> { +/// Returns `sqlx::Error` if the query fails. +pub async fn set_buyer(db: &PgPool, user_id: &str, value: bool) -> Result<(), sqlx::Error> { query!( "UPDATE users set is_buyer = $1 WHERE user_id = $2", value, @@ -81,9 +80,9 @@ pub async fn set_buyer(db: &PgPool, user_id: &str, value: bool) -> Result<()> { Ok(()) } -pub async fn get_or_create(db: &PgPool, user_id: &str) -> Result { +pub async fn get_or_create(db: &PgPool, user_id: &str) -> Result { create(db, user_id).await?; get(db, user_id) .await? - .ok_or_else(|| anyhow::anyhow!("Not able to get or create the user")) + .ok_or_else(|| sqlx::Error::RowNotFound) } diff --git a/src/events/bot/interaction_create.rs b/src/events/bot/interaction_create.rs index cc39a8d..55cf5e5 100644 --- a/src/events/bot/interaction_create.rs +++ b/src/events/bot/interaction_create.rs @@ -1,4 +1,4 @@ -use serenity::all::{Context, Interaction}; +use serenity::all::*; use sqlx::PgPool; use crate::commands::SlashCommand; use crate::config::EmojiConfig; diff --git a/src/events/bot/ready.rs b/src/events/bot/ready.rs index a70fc78..ae4d12f 100644 --- a/src/events/bot/ready.rs +++ b/src/events/bot/ready.rs @@ -11,14 +11,13 @@ use crate::models::bot::{ BotActivity, BotPresence }; -use anyhow::Result; pub struct ReadyHandler; async fn fetch_all_members( ctx: &Context, guild_id: GuildId, -) -> Result> { +) -> Result, serenity::Error> { let mut all_members: Vec = Vec::new(); let mut last_id: Option = None; diff --git a/src/main.rs b/src/main.rs index a9b1cf9..d7196f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,22 +5,22 @@ mod events; mod models; mod utils; -use dotenvy::dotenv; use events::Bot; -use serenity::Client; -use serenity::all::GatewayIntents; +use serenity::all::*; use sqlx::postgres::PgPoolOptions; use sqlx::{Pool, Postgres, migrate}; use std::env; -use tracing::{error, info}; -use tracing_subscriber::fmt; +use tracing::{ + info, + error +}; use self::config::emoji::EmojiConfig; #[tokio::main] async fn main() { - fmt::init(); - dotenv().ok(); + tracing_subscriber::fmt::init(); + dotenvy::dotenv().ok(); let token: String = env::var("DISCORD_TOKEN").expect("❌ | DISCORD_TOKEN missing (check the env file)"); diff --git a/src/utils/perm.rs b/src/utils/perm.rs index 11b78dc..05cb8c3 100644 --- a/src/utils/perm.rs +++ b/src/utils/perm.rs @@ -1,11 +1,9 @@ -use anyhow::Result; use sqlx::{ PgPool, query_scalar, }; -use tracing::warn; -pub async fn is_whitelist(db: &PgPool, user_id: &str, guild_id: &str) -> Result { +pub async fn is_whitelist(db: &PgPool, user_id: &str, guild_id: &str) -> Result { let result: Option = query_scalar( "SELECT TRUE FROM guild_users gu \ LEFT JOIN users u ON u.user_id = gu.user_id \ @@ -24,19 +22,9 @@ pub async fn is_whitelist(db: &PgPool, user_id: &str, guild_id: &str) -> Result< Ok(result.is_some()) } -pub async fn is_owner(db: &PgPool, user_id: &str) -> Result { - let result: bool = query_scalar( - "SELECT is_dev, is_buyer, is_owner FROM users WHERE user_id = $1 AND (is_dev = true OR is_buyer = true OR is_owner = true)", - ) - .bind(user_id) - .fetch_one(db) - .await?; - Ok(result) -} - -pub async fn is_buyer(db: &PgPool, user_id: &str) -> Result { +pub async fn is_owner(db: &PgPool, user_id: &str) -> Result { let result: Option = query_scalar( - "SELECT is_dev, is_buyer FROM users WHERE user_id = $1 AND (is_dev = true OR is_buyer = true)", + "SELECT TRUE FROM users WHERE user_id = $1 AND is_dev = true OR is_buyer = true OR is_owner = true", ) .bind(user_id) .fetch_optional(db) @@ -44,9 +32,19 @@ pub async fn is_buyer(db: &PgPool, user_id: &str) -> Result { Ok(result.is_some()) } -pub async fn is_dev(db: &PgPool, user_id: &str) -> Result { +pub async fn is_buyer(db: &PgPool, user_id: &str) -> Result { let result: Option = query_scalar( - "SELECT is_dev FROM users WHERE user_id = $1 AND is_dev = true", + "SELECT TRUE FROM users WHERE user_id = $1 AND is_dev = true OR is_buyer = true", + ) + .bind(user_id) + .fetch_optional(db) + .await?; + Ok(result.is_some()) +} + +pub async fn is_dev(db: &PgPool, user_id: &str) -> Result { + let result: Option = query_scalar( + "SELECT TRUE FROM users WHERE user_id = $1 AND is_dev = true", ) .bind(user_id) .fetch_optional(db)