diff --git a/.gitignore b/.gitignore index e5050ad..600833b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,15 @@ +# Build directory /target + +# IDE config directory .idea + +# Environment files .env + +# Local config files magnolia.cfg.yml -magnolia.cfg.*.yml \ No newline at end of file +magnolia.cfg.*.yml + +# Database files +*.sqlite \ No newline at end of file diff --git a/bot/src/commands/devforum_self_role.rs b/bot/src/commands/devforum_self_role.rs index 0e3bffa..70390ef 100644 --- a/bot/src/commands/devforum_self_role.rs +++ b/bot/src/commands/devforum_self_role.rs @@ -49,11 +49,9 @@ impl CommandHandler for DevForumSelfRole<'_> { "Click the `Update Roles` button below to claim your developer forum member role if you meet the eligibility criteria. - <@&{}> - Your **trust level** on the Roblox developer forum is `Member` (not to be confused with `Visitor`) -- <@&{}> - Your **trust level** on the Roblox developer forum is `Regular` - What is the developer forum? [**Learn more**](https://help.roblox.com/hc/articles/360000240223) - How do I \"level up\"? [**Learn more**](https://devforum.roblox.com/t/3170997)", ctx.cfg.roles.devforum_member, - ctx.cfg.roles.devforum_regular )) .thumbnail(ImageSource::attachment(&devforum_logo.filename)?) .build(); diff --git a/bot/src/components/verify_devforum_rank.rs b/bot/src/components/verify_devforum_rank.rs index 98ab7e6..71391b6 100644 --- a/bot/src/components/verify_devforum_rank.rs +++ b/bot/src/components/verify_devforum_rank.rs @@ -25,6 +25,8 @@ static ROVER_API_KEY: LazyLock = static DEVFORUM_COOKIE: LazyLock> = LazyLock::new(|| std::env::var("DEVFORUM_COOKIE").ok()); +const DEVFORUM_MEMBER_TRUST_LEVEL: u8 = 1; // Trust level for DevForum members + #[async_trait] impl ComponentHandler for VerifyDevForumRank<'_> { fn model() -> anyhow::Result { @@ -45,7 +47,7 @@ impl ComponentHandler for VerifyDevForumRank<'_> { .await? .roles; - // Respond early if the user doesn't have the verified role + // Respond early if the user doesn't have the verified role, // this is a quick check to avoid unnecessary API calls if let Some(r_id) = ctx.cfg.roles.roblox_verified { if !member_roles.contains(&r_id) { @@ -125,17 +127,10 @@ async fn get_response_content( return "Failed to fetch your DevForum data.".to_string(); }, }; + let is_member = devforum_data.user.trust_level >= DEVFORUM_MEMBER_TRUST_LEVEL; // Update the user's roles in the Discord server based on their trust level. - match update_user_roles( - guild_id, - author_id, - ctx, - &devforum_data.user.trust_level, - member_roles, - ) - .await - { + match update_user_roles(guild_id, author_id, ctx, is_member, member_roles).await { Ok(()) => format!( "Successfully updated your roles to match your DevForum trust level: `{}`", devforum_data.user.trust_level @@ -278,23 +273,31 @@ async fn fetch_devforum_data( /// * `guild_id` - The ID of the Discord server. /// * `user_id` - The ID of the Discord user. /// * `state` - The state of the bot. -/// * `trust_level` - The trust level of the user. +/// * `is_member` - Whether the user is a DevForum member. async fn update_user_roles( guild_id: Id, user_id: Id, state: &crate::Context, - trust_level: &DevForumTrustLevel, + is_member: bool, mut member_roles: Vec>, ) -> anyhow::Result<()> { - let roles = trust_level.roles(&state.cfg); - // Remove the roles that are no longer applicable - member_roles.retain(|role_id| !roles.remove.contains(role_id)); - - // Add the role if it is not already present - if let Some(role_id) = roles.add { - if !member_roles.contains(&role_id) { - member_roles.push(role_id); - } + let member_role_pos = member_roles + .iter() + .position(|&r| r == state.cfg.roles.devforum_member); + + match (is_member, member_role_pos) { + (true, None) => { + // If the user is a member but doesn't have the role, add it + member_roles.push(state.cfg.roles.devforum_member); + }, + (false, Some(pos)) => { + // If the user is not a member but has the role, remove it + member_roles.remove(pos); + }, + _ => { + // If the user is a member and has the role, do nothing + return Ok(()); + }, } // Update the guild member with the new roles @@ -341,50 +344,10 @@ struct DevForumAPIResponse { #[derive(Deserialize)] struct DevForumUser { - trust_level: DevForumTrustLevel, -} - -#[derive(Deserialize_repr, Debug)] -#[repr(u8)] -enum DevForumTrustLevel { - Visitor = 0, - Member = 1, - Regular = 2, - Staff, + trust_level: u8, } struct RoleData { add: Option>, - remove: Vec>, -} - -impl DevForumTrustLevel { - /// Returns the roles to add and remove based on the trust level. - fn roles(&self, cfg: &crate::Config) -> RoleData { - match self { - DevForumTrustLevel::Visitor => RoleData { - add: None, - remove: vec![cfg.roles.devforum_member, cfg.roles.devforum_regular], - }, - DevForumTrustLevel::Member => RoleData { - add: Some(cfg.roles.devforum_member), - remove: vec![cfg.roles.devforum_regular], - }, - DevForumTrustLevel::Regular | DevForumTrustLevel::Staff => RoleData { - add: Some(cfg.roles.devforum_regular), - remove: vec![cfg.roles.devforum_member], - }, - } - } -} - -impl std::fmt::Display for DevForumTrustLevel { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DevForumTrustLevel::Visitor => write!(f, "Visitor"), - DevForumTrustLevel::Member => write!(f, "Member"), - DevForumTrustLevel::Regular => write!(f, "Regular"), - DevForumTrustLevel::Staff => write!(f, "Staff"), - } - } + remove: Option>, } diff --git a/bot/src/config.rs b/bot/src/config.rs index 49a7d5a..ecd1d93 100644 --- a/bot/src/config.rs +++ b/bot/src/config.rs @@ -18,7 +18,6 @@ pub(crate) struct Config { #[derive(Deserialize, Debug)] pub(crate) struct RoleConfig { pub(crate) devforum_member: Id, - pub(crate) devforum_regular: Id, pub(crate) roblox_verified: Option>, }