From acfcae975e3bd3152460380a91770c7520f363f1 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 19:36:45 -0400
Subject: [PATCH] moved demote promote

---
 src/core/identity.rs | 557 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 551 insertions(+), 6 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 413ac3a..7ad804b 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -74,7 +74,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     };
 
     tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
-
+/*
     async fn cmd_promote(params : ExecBodyParams) {
         botlog::trace(
             "Called cmd promote",
@@ -267,7 +267,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             None,
         );
     }
-
+*/
     let tempb = BotCommand {
         module: BotModule(String::from("identity")),
         command: String::from("demote"), // command call name
@@ -283,7 +283,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     };
 
     tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
-
+/*
     async fn cmd_demote(params : ExecBodyParams) {
         botlog::debug(
             "Called cmd demote",
@@ -487,7 +487,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
     }
-
+*/
     let tempcomm = BotCommand {
         module: BotModule(String::from("identity")),
         command: String::from("getroles"), // command call name
@@ -503,7 +503,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     };
 
     tempcomm.add_core_to_modmgr(Arc::clone(&mgr)).await;
-
+/*
     async fn getroles(params : ExecBodyParams) {
         botlog::debug(
             "Called cmd getroles",
@@ -643,7 +643,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         // [ ] NOTE : After the above, I should receive only the roles in the context of the current channel I received this ideally and maybe BotAdmin ; not outside
     }
-
+*/
     botlog::trace(
         "End of Init MOdule add",
         Some("identity.rs > init ".to_string()),
@@ -653,6 +653,551 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     Log::flush();
 }
 
+
+
+async fn cmd_promote(params : ExecBodyParams) {
+    botlog::trace(
+        "Called cmd promote",
+        Some("identity.rs > cmd_prommote()".to_string()),
+        Some(&params.msg),
+    );
+
+    // -- If the BotCommand.command was called (e.g., promote) & required roles were validated OUTSIDE of this call
+    // , this is the current function body to execute
+
+    /*
+    - `promote` / `demote`
+        - [ ] `SupMod` & `Broadcaster` & `BotAdmin` can run
+        - [ ] `UserRole`s that can run, can
+            - [ ] run `promote` on a regular `Chatter` to make them a `Mod`
+            - [ ] run `demote` on a `Mod` to make them a `Chatter`
+        - [ ] Only `BotAdmin` can :
+            - [ ] target themselves to `promote` / `demote` , in the case that they want to make themselves either a `Mod` or `SupMod` for the channel temporarily
+            - [ ] `promote admin <Chatter>` to assign them `BotAdmin` role
+        - `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` or `promote` the other way
+     */
+
+    /*
+    Usage :
+
+        promote <user>
+        promote -m <user>
+        promote -mod <user>
+
+        demote <user>
+
+        promote -v <user>
+        promote -vip <user>
+
+        promote -admin <user>
+
+     */
+
+    //  println!("{}",params.msg.message_text);
+    botlog::trace(
+        format!("Twich Message > {}", params.msg.message_text).as_str(),
+        Some("identity.rs > cmd_promote()".to_string()),
+        None,
+    );
+
+    let sendername = params.msg.clone().sender.name;
+
+    let mut argv = params.msg.message_text.split(' ');
+
+    argv.next(); // Skip the command name
+
+    let arg1 = argv.next();
+
+    let arg2 = argv.next();
+
+    let mut sender_badge: Option<ChatBadge> = None;
+
+    for b in &params.msg.badges {
+        if b.name == "moderator" {
+            sender_badge = Some(ChatBadge::Mod);
+        } else if b.name == "broadcaster" {
+            sender_badge = Some(ChatBadge::Broadcaster);
+        } else if b.name == "vip" {
+            sender_badge = Some(ChatBadge::VIP);
+        }
+    };
+
+    let targetchnl = params.msg.channel_login.to_lowercase();
+
+    /*
+
+      [x] 1. Get trgusr (regardless of -admin flag)
+      [x] 2. promote trguser
+      [x] 3. Output resulting change
+
+    */
+
+    // [x] 1. Get trgusr (regardless of -admin flag)
+
+    // let targetusr = if arg1 == Some("-admin") { arg2 } else { arg1 };
+    let targetusr = if 
+            arg1 == Some("-admin") 
+            || arg1 == Some("-v") 
+            || arg1 == Some("-vip") 
+            || arg1 == Some("-m") 
+            || arg1 == Some("-mod") 
+            { arg2 } 
+            else { arg1 };
+
+    // [x] 2. promote trguser
+
+    // [x] Get a required lock first
+
+    let botlock = params.bot.read().await;
+    let id = botlock.get_identity();
+    let idlock = id.read().await;
+
+    let rslt = match targetusr {
+        Some(targetusr) => {
+            botlog::debug(
+                "running promote()",
+                Some("identity.rs > cmd_promote()".to_string()),
+                None,
+            );
+
+            Log::flush();
+
+
+            // // Believe this is just using this as a Constaint depending on input
+            // let target_bot_admin_role = 
+            //     if arg1 == Some("-admin") {
+            //         Some(UserRole::BotAdmin)
+            //     } else {
+            //         None
+            //     };
+
+            let target_role = 
+                if arg1 == Some("-admin") {
+                    Some(UserRole::BotAdmin)
+                } else if arg1 == Some("-vip") || arg1 == Some("-v") {
+                    Some(UserRole::VIP(Channel(targetchnl.clone())))
+                } else {
+                    None // [x] Internal promote() logic automatically considers trg_role targetting -mod or -m
+                };
+
+            // let target_bot_admin_role = 
+            // if arg1 == Some("-admin") {
+            //     Some(UserRole::BotAdmin)
+            // } else if arg1 == Some("-v") {
+            //     Some(UserRole::VIP)
+            // } else {
+            //     None
+            // };
+
+            idlock
+                .promote(
+                    sendername.clone(),
+                    &sender_badge,
+                    targetusr.to_string(),
+                    Some(Channel(targetchnl.clone())),
+                    target_role,
+                )
+                .await
+        }
+
+        None => {
+            botlog::debug(
+                "No Targer User argument",
+                Some("identity.rs > cmd_demote()".to_string()),
+                None,
+            );
+            Log::flush();
+
+            ChangeResult::NoChange("No Targer User".to_string())
+        }
+    };
+
+    // [x] 3. Output resulting change
+
+    let outmsg = match rslt {
+        ChangeResult::Success(a) => {
+            format!("o7 Successfully promoted : {a}")
+        }
+        ChangeResult::Failed(a) => {
+            format!("PoroSad failed to promote : {a}")
+        }
+        ChangeResult::NoChange(a) => {
+            format!("uuh No Promotion Change : {a}")
+        }
+    };
+
+    botlog::debug(
+        outmsg.as_str(),
+        Some("identity.rs > cmd_prommote()".to_string()),
+        Some(&params.msg),
+    );
+
+    // We should call a notification around here
+
+    botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+        outmsg.to_string()
+        ),
+    params.clone(),
+    ).await;
+
+
+    botlog::trace(
+        "End of cmd_promote()",
+        Some("identity.rs > cmd_prommote()".to_string()),
+        None,
+    );
+}
+
+
+
+async fn cmd_demote(params : ExecBodyParams) {
+    botlog::debug(
+        "Called cmd demote",
+        Some("identity.rs > cmd_demote()".to_string()),
+        Some(&params.msg),
+    );
+    Log::flush();
+
+    // -- If the BotCommand.command was called (e.g., demote) & required roles were validated OUTSIDE of this call
+    // , this is the current function body to execute
+
+    /*
+    - `promote` / `demote`
+        - [ ] `SupMod` & `Broadcaster` & `BotAdmin` can run
+        - [ ] `UserRole`s that can run, can
+            - [ ] run `promote` on a regular `Chatter` to make them a `Mod`
+            - [ ] run `demote` on a `Mod` to make them a `Chatter`
+        - [ ] Only `BotAdmin` can :
+            - [ ] target themselves to `promote` / `demote` , in the case that they want to make themselves either a `Mod` or `SupMod` for the channel temporarily
+            - [ ] `promote admin <Chatter>` to assign them `BotAdmin` role
+        - `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` or `promote` the other way
+     */
+
+    /*
+    Usage :
+
+        promote <user>
+
+        demote <user>
+
+        demote -m <user>
+        demote -mod <user>
+
+        demote -v <user>
+        demote -vip <user>
+
+        // promote -admin <user>
+
+        
+
+     */
+
+    // [x] Unwraps arguments from message
+
+    let (arg1, arg2) = {
+        let mut argv = params.msg.message_text.split(' ');
+
+        argv.next(); // Skip the command name
+
+        let arg1 = argv.next();
+
+        let arg2 = argv.next();
+
+        (arg1, arg2)
+    };
+
+    // ---
+
+    /*
+    -   [x] 1. Parse out the following
+            - Sender (e.g., Name & Badge)
+            - Target User (arg1)
+            - Target Channel (current channel)
+            - Msg or Msg.Message_Text (for later)
+
+    -   [x] 2. Run Demote()
+        - within demote(), getspecialuserroles() is called on both the sender and the target
+            - getspecialuserroles() only sends current db , while canuserrun() may change db depending on the most current state of the sender
+            - getspecialuserroles also borrows the sender's badge to evaluate
+
+    -   [x] 3. Take ChangeResult and output response
+
+    */
+
+    /*
+
+    -   [x] 1. Parse out the following
+            - Sender (e.g., Name & Badge)
+            - Target User (arg1)
+            - Target Channel (current channel)
+            - (no need) Msg or Msg.Message_Text (for later)
+
+     */
+
+    let sendername = params.msg.clone().sender.name;
+
+    let mut sender_badge_mut: Option<ChatBadge> = None;
+
+    for b in &params.msg.badges {
+        if b.name == "moderator" {
+            sender_badge_mut = Some(ChatBadge::Mod);
+        } else if b.name == "broadcaster" {
+            sender_badge_mut = Some(ChatBadge::Broadcaster);
+        } else if b.name == "vip" {
+            sender_badge_mut = Some(ChatBadge::VIP);
+        }
+    };
+
+    let sender_badge = sender_badge_mut;
+
+   
+    let targetchnl = params.msg.channel_login.to_lowercase();
+
+
+    // let targetusr = arg1;
+    let targetusr = if 
+        arg1 == Some("-v") 
+        || arg1 == Some("-vip") 
+        || arg1 == Some("-m") 
+        || arg1 == Some("-mod") 
+        { arg2 } 
+        else { arg1 };
+
+    // Note : At the moment, no handling of -admin
+    let target_role =  
+        if arg1 == Some("-vip") || arg1 == Some("-v") {
+            Some(UserRole::VIP(Channel(targetchnl.clone())))
+        } else {
+            None // [x] Internal promote() logic automatically considers trg_role targetting -mod or -m
+        };
+
+
+
+    /*
+
+    - [x] 2. Run Demote()
+        - within demote(), getspecialuserroles() is called on both the sender and the target
+            - getspecialuserroles() only sends current db , while canuserrun() may change db depending on the most current state of the sender
+            - getspecialuserroles also borrows the sender's badge to evaluate
+
+
+     */
+
+    // [x] Get a required lock first
+
+    let botlock = params.bot.read().await;
+    let id = botlock.get_identity();
+    let idlock = id.read().await;
+
+    let rslt = match targetusr {
+        Some(targetusr) => {
+            botlog::debug(
+                "running demote()",
+                Some("identity.rs > cmd_demote()".to_string()),
+                None,
+            );
+            Log::flush();
+
+            idlock
+                .demote(
+                    sendername.clone(),
+                    &sender_badge,
+                    targetusr.to_string(),
+                    Some(Channel(targetchnl.clone())),
+                    target_role,
+                )
+                .await
+        }
+
+        None => {
+            botlog::debug(
+                "No Targer User argument",
+                Some("identity.rs > cmd_demote()".to_string()),
+                None,
+            );
+            Log::flush();
+
+            ChangeResult::NoChange("No Targer User".to_string())
+        }
+    };
+
+    /*
+
+    - [x] 3. Take ChangeResult and output response
+
+     */
+
+    let outmsg = match rslt {
+        ChangeResult::Success(a) => {
+            format!("o7 Successfully demoted : {a}")
+        }
+        ChangeResult::Failed(a) => {
+            format!("PoroSad failed to demote : {a}")
+        }
+        ChangeResult::NoChange(a) => {
+            format!("uuh No Demotion Change : {a}")
+        }
+    };
+
+    botlog::debug(
+        outmsg.as_str(),
+        Some("identity.rs > cmd_demote()".to_string()),
+        Some(&params.msg),
+    );
+
+    botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+        outmsg.to_string()
+        ),
+    params.clone(),
+    ).await;
+
+
+}
+
+
+
+async fn getroles(params : ExecBodyParams) {
+    botlog::debug(
+        "Called cmd getroles",
+        Some("identity.rs > cmd_getroles()".to_string()),
+        Some(&params.msg),
+    );
+
+    /*
+    Usage
+
+    getroles <user> <Channel>
+    - If channel is provided, provide roles for that channel specifically
+
+     */
+
+
+    let mut argv = params.msg.message_text.split(' ');
+
+    argv.next(); // Skip the command name
+
+    let arg1 = argv.next();
+
+    let targetuser = match arg1 {
+        None => return, // exit if no arguments
+        Some(arg) => arg,
+    };
+
+    let arg2 = argv.next();
+
+    let targetchnl = arg2;
+
+    let botlock = params.bot.read().await;
+
+    let id = botlock.get_identity();
+
+    let idlock = id.read().await;
+
+    let sproles = match targetchnl {
+        None => {
+            // [ ] If targetchnl is not provided, default to pulling the current channel
+            idlock
+                .getspecialuserroles(
+                    String::from(targetuser),
+                    Some(Channel(params.msg.channel_login.to_lowercase())),
+                )
+                .await
+        }
+        Some(targetchnl) => {
+            // [x] gets special roles for caller
+            let callersproles = idlock
+                .getspecialuserroles(
+                    params.msg.sender.name.to_lowercase(),
+                    Some(Channel(targetchnl.to_lowercase().to_string())),
+                )
+                .await;
+
+            // Below appears to be validating if getroles() should run based on caller's specific roles
+            // - No Need to add VIP here
+            if callersproles.contains(&UserRole::Mod(Channel(
+                targetchnl.to_lowercase().to_string(),
+            ))) || callersproles.contains(&UserRole::SupMod(Channel(
+                targetchnl.to_lowercase().to_string(),
+            ))) || callersproles.contains(&UserRole::Broadcaster)
+            {
+                idlock
+                    .getspecialuserroles(
+                        String::from(targetuser),
+                        Some(Channel(targetchnl.to_lowercase())),
+                    )
+                    .await
+            } else {
+                // Otherwise, don't get the target channel, return the current channel instead
+                idlock
+                    .getspecialuserroles(
+                        String::from(targetuser),
+                        Some(Channel(params.msg.channel_login.to_lowercase())),
+                    )
+                    .await
+            }
+        }
+    };
+
+    botlog::debug(
+        &format!("User roles of Target Chatter >> {:?}", sproles),
+        Some("identity.rs > init > getroles()".to_string()),
+        Some(&params.msg),
+    );
+
+    botlog::trace(
+        "Evaluating special roles",
+        Some("identity.rs > init > getroles()".to_string()),
+        Some(&params.msg),
+    );
+
+    let outmsg = if ((targetuser.to_lowercase() == params.msg.channel_login.to_lowercase())
+        && arg2.is_none())
+        || (arg2.is_some() && arg2.unwrap() == targetuser.to_lowercase())
+    {
+        // First evaluates if they're broadcaster
+
+        let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string();
+
+        // Below appears to be validating if getroles() should run based on caller's specific roles
+        // - No Need to add VIP here
+        if sproles.contains(&UserRole::Mod(Channel(
+            params.msg.channel_login.to_lowercase(),
+        ))) || sproles.contains(&UserRole::SupMod(Channel(
+            params.msg.channel_login.to_lowercase(),
+        ))) || sproles.contains(&UserRole::BotAdmin)
+        {
+            outmsg += format!("Target chatter's user roles are : {:?}", sproles).as_str();
+        }
+        outmsg
+    } else if sproles.contains(&UserRole::Mod(Channel(
+        params.msg.channel_login.to_lowercase(),
+    ))) || sproles.contains(&UserRole::SupMod(Channel(
+        params.msg.channel_login.to_lowercase(),
+    ))) || sproles.contains(&UserRole::BotAdmin)
+    {
+        format!("Target chatter's user roles are : {:?}", sproles)
+    } else {
+        "Target chatter has no special roles LULE ".to_string()
+    };
+
+    botlog::debug(
+        format!("Chat Say Reply message : {}", outmsg).as_str(),
+        Some("identity.rs > init > getroles()".to_string()),
+        Some(&params.msg),
+    );
+
+    botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+        outmsg.to_string()
+        ),
+    params.clone(),
+    ).await;
+
+
+    // [ ] NOTE : After the above, I should receive only the roles in the context of the current channel I received this ideally and maybe BotAdmin ; not outside
+}
+
+
+
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum UserRole {
     Chatter,