From fb1617d6d9c07e14e70a024c02b255b78b0079e2 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Sun, 17 Mar 2024 18:40:12 -0300
Subject: [PATCH 01/98] minor spelling mistake

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index c736061..8637fdc 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ test ModulatingForceBot
 
 ```
 login_name = <botname>
-access_token = <oath token>
+access_token = <oauth token>
 bot_channels = <chnl1>,<chnl2>
 prefix = <prefix>
 ```
\ No newline at end of file

From 5fb373c522abbf350596e7c0ed98d7b4ec015513 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Sun, 17 Mar 2024 19:12:33 -0300
Subject: [PATCH 02/98] bot admins change

---
 src/core/identity.rs | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 877fb6c..6392eb3 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -11,10 +11,19 @@ use crate::core::bot_actions::actions_util::{self, BotAR};
 use crate::core::botinstance::ChType;
 use crate::core::botlog;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
+use dotenv::dotenv;
+use std::env;
 
 fn adminvector() -> Vec<String> {
-    vec![String::from("ModulatingForce")]
-    //vec![]
+    // vec![String::from("ModulatingForce")]
+    // //vec![]
+    dotenv().ok();
+    let mut admins = Vec::new();
+
+    for admin in env::var("bot_admins").unwrap().split(',') {
+        admins.push(String::from(admin))
+    }
+    admins
 }
 
 pub async fn init(mgr: Arc<ModulesManager>) {

From f7881fa07d5ff5a6d1295eaf80c88214437df746 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 17 Mar 2024 19:29:22 -0400
Subject: [PATCH 03/98] adj adminvector()

---
 README.md            |  1 +
 src/core/identity.rs | 17 +++++++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 8637fdc..33fdb59 100644
--- a/README.md
+++ b/README.md
@@ -12,4 +12,5 @@ login_name = <botname>
 access_token = <oauth token>
 bot_channels = <chnl1>,<chnl2>
 prefix = <prefix>
+bot_admins = <admins>
 ```
\ No newline at end of file
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 6392eb3..42bc4c7 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -20,9 +20,22 @@ fn adminvector() -> Vec<String> {
     dotenv().ok();
     let mut admins = Vec::new();
 
-    for admin in env::var("bot_admins").unwrap().split(',') {
-        admins.push(String::from(admin))
+    // for admin in env::var("bot_admins").unwrap().split(',') {
+    //     admins.push(String::from(admin))
+    // }
+
+    // 03.17 - Forcen - Suggesting below instead : 
+    /*
+        - this will push only if env::var() returns Ok() ; 
+            otherwise (like in Err(_)) do nothing
+     */
+
+    if let Ok(value) = env::var("bot_admins") {
+        for admin in value.split(',') {
+            admins.push(String::from(admin))        
+        }
     }
+
     admins
 }
 

From eb8877f0c1b154288f0c2343ec076ec18ae0fb50 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 20 Mar 2024 23:20:46 -0400
Subject: [PATCH 04/98] ModGroup enum

---
 src/core/botmodules.rs | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 0bfe4fa..2fa8945 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -45,6 +45,12 @@ pub enum ModType {
     BotModule(String),
 }
 
+#[derive(Debug, PartialEq, Eq, Hash, Clone)]
+pub enum ModGroup {
+    Core,
+    Custom,
+}
+
 #[derive(Debug)]
 pub enum StatusLvl {
     Instance,
@@ -77,6 +83,8 @@ impl BotAction {
 pub trait BotActionTrait {
     async fn add_to_bot(self, bot: BotInstance);
     async fn add_to_modmgr(self, modmgr: Arc<ModulesManager>);
+    async fn add_core_to_bot(self, bot: BotInstance);
+    async fn add_core_to_modmgr(self, modmgr: Arc<ModulesManager>);
 }
 
 pub struct BotCommand {
@@ -105,6 +113,16 @@ impl BotActionTrait for BotCommand {
             .add_botaction(self.module.clone(), BotAction::C(self))
             .await
     }
+
+    async fn add_core_to_bot(self, bot: BotInstance) {
+        self.add_core_to_modmgr(bot.botmodules).await;
+    }
+
+    async fn add_core_to_modmgr(self, modmgr: Arc<ModulesManager>) {
+        modmgr
+            .add_core_act(self.module.clone(), BotAction::C(self))
+            .await
+    }
 }
 
 pub struct Listener {
@@ -142,13 +160,24 @@ impl BotActionTrait for Listener {
             .add_botaction(self.module.clone(), BotAction::L(self))
             .await;
     }
+
+    async fn add_core_to_bot(self, bot: BotInstance) {
+        self.add_core_to_modmgr(bot.botmodules).await;
+    }
+
+    async fn add_core_to_modmgr(self, modmgr: Arc<ModulesManager>) {
+        modmgr
+            .add_core_act(self.module.clone(), BotAction::L(self))
+            .await
+    }
 }
 
 #[derive(Debug)]
 pub struct Routine {}
 
 pub struct ModulesManager {
-    statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
+    // statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
+    statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<ModStatusType>>>>,
     pub botactions: Arc<RwLock<HashMap<ModType, Vec<BotAction>>>>,
 }
 
@@ -220,6 +249,14 @@ impl ModulesManager {
     }
 
     pub async fn add_botaction(&self, in_module: ModType, in_action: BotAction) {
+        self.int_add_botaction(in_module,ModGroup::Custom,in_action).await;
+    }
+
+    pub async fn add_core_act(&self, in_module: ModType, in_action: BotAction) {
+        self.int_add_botaction(in_module,ModGroup::Core,in_action).await;
+    }
+
+    async fn int_add_botaction(&self, in_module: ModType, in_modgroup: ModGroup, in_action: BotAction) {
         botlog::trace(
             "Add botaction called",
             Some("ModulesManager > init()".to_string()),
@@ -300,7 +337,8 @@ impl ModulesManager {
         }
 
         let mut dbt = self.statusdb.write().await;
-        let statusvector = dbt.entry(in_module.clone()).or_insert(Vec::new());
+        // 
+        let statusvector = dbt.entry((in_module.clone(),in_modgroup.clone())).or_insert(Vec::new());
 
         statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level
 

From dda0050513926fea695379823b871504219ad8a3 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 20 Mar 2024 23:26:05 -0400
Subject: [PATCH 05/98] identity adds core modules

---
 src/core/identity.rs | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index f5e710b..b302a7e 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -67,7 +67,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ],
     };
 
-    tempb.add_to_modmgr(Arc::clone(&mgr)).await;
+    // tempb.add_to_modmgr(Arc::clone(&mgr)).await;
+    tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
     async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) {
         botlog::trace(
@@ -238,7 +239,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ],
     };
 
-    tempb.add_to_modmgr(Arc::clone(&mgr)).await;
+    // tempb.add_to_modmgr(Arc::clone(&mgr)).await;
+    // add_core_to_modmgr
+    tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
     async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) {
         botlog::debug(
@@ -428,7 +431,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ],
     };
 
-    tempcomm.add_to_modmgr(Arc::clone(&mgr)).await;
+    // tempcomm.add_to_modmgr(Arc::clone(&mgr)).await;
+    // add_core_to_modmgr
+    tempcomm.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
     async fn getroles(bot: BotAR, msg: PrivmsgMessage) {
         botlog::debug(

From ca3bca9ae6e67fa2a564243bf8f54bfd671c50ed Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 20 Mar 2024 23:32:05 -0400
Subject: [PATCH 06/98] modgroup default statuses

---
 src/core/botmodules.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 2fa8945..870fc98 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -340,7 +340,12 @@ impl ModulesManager {
         // 
         let statusvector = dbt.entry((in_module.clone(),in_modgroup.clone())).or_insert(Vec::new());
 
-        statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level
+        match in_modgroup {
+            ModGroup::Core => statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
+            ModGroup::Custom => statusvector.push(ModStatusType::Disabled(StatusLvl::Instance)),
+        }
+
+        // statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level
 
         let mut a = self.botactions.write().await;
         let modactions = a.entry(in_module.clone()).or_insert(Vec::new());

From b353589576e2bb224555ab4e626321fa675e5617 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 20 Mar 2024 23:35:56 -0400
Subject: [PATCH 07/98] refactor statustype

---
 src/core/botmodules.rs | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 870fc98..fdbddcf 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -58,7 +58,7 @@ pub enum StatusLvl {
 }
 
 #[derive(Debug)]
-pub enum ModStatusType {
+pub enum StatusType {
     Enabled(StatusLvl),
     Disabled(StatusLvl),
 }
@@ -177,7 +177,7 @@ pub struct Routine {}
 
 pub struct ModulesManager {
     // statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
-    statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<ModStatusType>>>>,
+    statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<StatusType>>>>,
     pub botactions: Arc<RwLock<HashMap<ModType, Vec<BotAction>>>>,
 }
 
@@ -226,7 +226,7 @@ impl ModulesManager {
         mgrarc
     }
 
-    pub fn modstatus(&self, _: ModType, _: ChType) -> ModStatusType {
+    pub fn modstatus(&self, _: ModType, _: ChType) -> StatusType {
         // Example usage : botmanager.modstatus(
         //     BotModule("GambaCore"),
         //     Channel("modulatingforce")
@@ -234,15 +234,15 @@ impl ModulesManager {
         // - The ModStatusType checks in the context of the given channel ,
         //  but also validates based on wheher the module is disabled at a bot instance
         //  level as well
-        ModStatusType::Enabled(StatusLvl::Instance)
+        StatusType::Enabled(StatusLvl::Instance)
     }
 
-    pub fn togglestatus(&self, _: ModType, _: ChType) -> ModStatusType {
+    pub fn togglestatus(&self, _: ModType, _: ChType) -> StatusType {
         // enables or disables based on current status
-        ModStatusType::Enabled(StatusLvl::Instance)
+        StatusType::Enabled(StatusLvl::Instance)
     }
 
-    pub fn setstatus(&self, _: ModType, _: ModStatusType) -> Result<&str, Box<dyn Error>> {
+    pub fn setstatus(&self, _: ModType, _: StatusType) -> Result<&str, Box<dyn Error>> {
         // sets the status based given ModSatusType
         // e.g., b.setstatus(BodModule("GambaCore"), Enabled(Channel("modulatingforce"))).expect("ERROR")
         Ok("")
@@ -341,8 +341,8 @@ impl ModulesManager {
         let statusvector = dbt.entry((in_module.clone(),in_modgroup.clone())).or_insert(Vec::new());
 
         match in_modgroup {
-            ModGroup::Core => statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
-            ModGroup::Custom => statusvector.push(ModStatusType::Disabled(StatusLvl::Instance)),
+            ModGroup::Core => statusvector.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
+            ModGroup::Custom => statusvector.push(StatusType::Disabled(StatusLvl::Instance)),
         }
 
         // statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level

From a066329730529a475a467fa1ea13f8495b834717 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 00:05:52 -0400
Subject: [PATCH 08/98] botmodules helper fns

---
 src/core/botinstance.rs | 11 ++++++++-
 src/core/botmodules.rs  | 54 ++++++++++++++++++++++++++++++++++-------
 src/core/identity.rs    | 14 +++++------
 3 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 144e8ee..2e30421 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -19,12 +19,21 @@ use crate::core::ratelimiter::RateLimiter;
 
 use crate::core::bot_actions::actions_util::BotAR;
 use crate::core::botmodules::ModulesManager;
-use crate::core::identity::{ChangeResult, IdentityManager, Permissible};
+use crate::core::identity::{IdentityManager, Permissible};
 
 use crate::core::botlog;
 use crate::core::chat::Chat;
 
 
+#[derive(Debug, PartialEq, Eq)]
+pub enum ChangeResult {
+    Success(String),
+    Failed(String),
+    NoChange(String),
+}
+
+
+
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum ChType {
     Channel(String),
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index fdbddcf..746c673 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -22,7 +22,7 @@ Example
 use core::panic;
 
 use std::collections::HashMap;
-use std::error::Error;
+// use std::error::Error;
 use std::sync::Arc;
 
 use twitch_irc::message::PrivmsgMessage;
@@ -32,7 +32,7 @@ use tokio::sync::RwLock;
 use async_trait::async_trait;
 
 use self::bot_actions::actions_util::BotAR;
-use crate::core::botinstance::{BotInstance, ChType};
+use crate::core::botinstance::{BotInstance, ChType,ChangeResult};
 use crate::core::botlog;
 use crate::core::identity;
 
@@ -40,6 +40,9 @@ use crate::core::bot_actions;
 pub use ChType::Channel;
 pub use ModType::BotModule;
 
+// use super::identity::ChangeResult;
+
+
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum ModType {
     BotModule(String),
@@ -237,17 +240,50 @@ impl ModulesManager {
         StatusType::Enabled(StatusLvl::Instance)
     }
 
-    pub fn togglestatus(&self, _: ModType, _: ChType) -> StatusType {
-        // enables or disables based on current status
-        StatusType::Enabled(StatusLvl::Instance)
+    // pub fn togglestatus(&self, _: ModType, _: ChType) -> StatusType {
+    //     // enables or disables based on current status
+    //     StatusType::Enabled(StatusLvl::Instance)
+    // }
+
+    // pub fn setstatus(&self, _: ModType, _: StatusType) -> Result<&str, Box<dyn Error>> {
+    //     // sets the status based given ModSatusType
+    //     // e.g., b.setstatus(BodModule("GambaCore"), Enabled(Channel("modulatingforce"))).expect("ERROR")
+    //     Ok("")
+    // }
+
+    pub fn set_instance_disabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
+        // at Instance level
+        // - If core module, do nothing
+        (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub fn setstatus(&self, _: ModType, _: StatusType) -> Result<&str, Box<dyn Error>> {
-        // sets the status based given ModSatusType
-        // e.g., b.setstatus(BodModule("GambaCore"), Enabled(Channel("modulatingforce"))).expect("ERROR")
-        Ok("")
+    pub fn force_disabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
+        // Disables the module at Instance level, and removes all Enabled/Disabled at Channel level
+        //  - Bot Moderators MUST Re-enable if they were enabled before
+        //  - If core module, do nothing
+        (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
+    pub fn set_instance_enabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
+        // at Instance level
+        //  - If core module, do nothing
+        (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+    }
+
+    pub fn set_ch_disabled(&self, _in_module: ModType , _in_chnl: ChType) -> (StatusType,ChangeResult) {
+        // at Instance level
+        //  - If core module, do nothing
+        (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+    }
+
+    pub fn set_ch_enabled(&self, _in_module: ModType , _in_chnl: ChType) -> (StatusType,ChangeResult) {
+        // at Instance level
+        //  - If core module, do nothing
+        (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+    }
+
+
+
     pub async fn add_botaction(&self, in_module: ModType, in_action: BotAction) {
         self.int_add_botaction(in_module,ModGroup::Custom,in_action).await;
     }
diff --git a/src/core/identity.rs b/src/core/identity.rs
index b302a7e..65a5088 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -8,7 +8,7 @@ use twitch_irc::message::PrivmsgMessage;
 use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util::{self, BotAR};
-use crate::core::botinstance::ChType;
+use crate::core::botinstance::{ChType,ChangeResult};
 use crate::core::botlog;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
@@ -608,12 +608,12 @@ pub enum ChatBadge {
     Mod,
 }
 
-#[derive(Debug, PartialEq, Eq)]
-pub enum ChangeResult {
-    Success(String),
-    Failed(String),
-    NoChange(String),
-}
+// #[derive(Debug, PartialEq, Eq)]
+// pub enum ChangeResult {
+//     Success(String),
+//     Failed(String),
+//     NoChange(String),
+// }
 
 impl IdentityManager {
     pub fn init() -> IdentityManager {

From 1b44ec4f4c62196de64efea9e90cdd6a8da6a524 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 00:11:24 -0400
Subject: [PATCH 09/98] reorg statusdb

---
 src/core/botmodules.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 746c673..8fdf96c 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -180,7 +180,8 @@ pub struct Routine {}
 
 pub struct ModulesManager {
     // statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
-    statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<StatusType>>>>,
+    // statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<StatusType>>>>,
+    statusdb: Arc<RwLock<HashMap<ModType, (ModGroup, Vec<StatusType>)>>>,
     pub botactions: Arc<RwLock<HashMap<ModType, Vec<BotAction>>>>,
 }
 
@@ -374,11 +375,11 @@ impl ModulesManager {
 
         let mut dbt = self.statusdb.write().await;
         // 
-        let statusvector = dbt.entry((in_module.clone(),in_modgroup.clone())).or_insert(Vec::new());
+        let statusvector = dbt.entry(in_module.clone()).or_insert((in_modgroup.clone(),Vec::new()));
 
         match in_modgroup {
-            ModGroup::Core => statusvector.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
-            ModGroup::Custom => statusvector.push(StatusType::Disabled(StatusLvl::Instance)),
+            ModGroup::Core => statusvector.1.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
+            ModGroup::Custom => statusvector.1.push(StatusType::Disabled(StatusLvl::Instance)),
         }
 
         // statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level

From 5280d18702e767d380007ff2e1e965aa10c1440e Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 02:13:23 -0400
Subject: [PATCH 10/98] cont helper fns

---
 src/core/botmodules.rs | 120 +++++++++++++++++++++++++++++++++++------
 1 file changed, 105 insertions(+), 15 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 8fdf96c..78db77e 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -25,6 +25,7 @@ use std::collections::HashMap;
 // use std::error::Error;
 use std::sync::Arc;
 
+use futures::stream::iter;
 use twitch_irc::message::PrivmsgMessage;
 
 use tokio::sync::RwLock;
@@ -54,13 +55,13 @@ pub enum ModGroup {
     Custom,
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum StatusLvl {
     Instance,
-    _Ch(ChType),
+    Ch(ChType),
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum StatusType {
     Enabled(StatusLvl),
     Disabled(StatusLvl),
@@ -252,17 +253,87 @@ impl ModulesManager {
     //     Ok("")
     // }
 
-    pub fn set_instance_disabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
+    pub async fn set_instance_disabled(&self, in_module: ModType) -> (StatusType,ChangeResult) {
         // at Instance level
         // - If core module, do nothing
-        (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+
+        // self.satusdb.
+
+        let mut dbt = self.statusdb.write().await;
+         
+        // let a = dbt.entry(in_module.clone()).;
+        let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
+
+        match mgrp {
+            ModGroup::Core => {
+                (
+                    StatusType::Enabled(StatusLvl::Instance),
+                    ChangeResult::Failed("Core Modules cannot be disabled".to_string())
+                )
+            },
+            ModGroup::Custom  => {
+                // remove all instance level pattern for the module
+                while let Some(index) = statusvector
+                        .iter()
+                        .position(|x| (*x == StatusType::Enabled(StatusLvl::Instance)) || (*x == StatusType::Disabled(StatusLvl::Instance))) {
+
+                            statusvector.remove(index);
+                        }
+                statusvector.push(StatusType::Disabled(StatusLvl::Instance));
+
+                (
+                    StatusType::Disabled(StatusLvl::Instance),
+                    ChangeResult::Success("Disabled at Instance".to_string())
+                )
+            },
+        }
+        
+        // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub fn force_disabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
-        // Disables the module at Instance level, and removes all Enabled/Disabled at Channel level
+    pub async fn force_disable(&self, in_module: ModType) -> (StatusType,ChangeResult) {
+        // Disables the module at Instance level, and removes all Enabled at Channel level
         //  - Bot Moderators MUST Re-enable if they were enabled before
         //  - If core module, do nothing
-        (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+
+        let mut dbt = self.statusdb.write().await;
+         
+        // let a = dbt.entry(in_module.clone()).;
+        let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
+
+        match mgrp {
+            ModGroup::Core => {
+                (
+                    StatusType::Enabled(StatusLvl::Instance),
+                    ChangeResult::Failed("Core Modules cannot be disabled".to_string())
+                )
+            },
+            ModGroup::Custom  => {
+                // remove all instance level pattern & Enabled Channel patterns for the module
+                // Disabled at Channel level might be fine? That way if it gets Enabled at instance level, channel level disables are uninterrupted
+                while let Some(index) = statusvector
+                        .iter()
+                        .position(|x| 
+                            if (*x == StatusType::Enabled(StatusLvl::Instance)) 
+                            || (*x == StatusType::Disabled(StatusLvl::Instance)) {
+                                true
+                            } else if let StatusType::Enabled(StatusLvl::Ch(_)) = (*x).clone() {
+                                true
+                            } else {false}
+                        ) 
+                {
+                    statusvector.remove(index);
+                }
+                statusvector.push(StatusType::Disabled(StatusLvl::Instance));
+
+                (
+                    StatusType::Disabled(StatusLvl::Instance),
+                    ChangeResult::Success("Disabled at Instance".to_string())
+                )
+            },
+        }
+
+        // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
     pub fn set_instance_enabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
@@ -293,6 +364,23 @@ impl ModulesManager {
         self.int_add_botaction(in_module,ModGroup::Core,in_action).await;
     }
 
+
+    pub async fn affirm_in_statusdb(&self,in_module:ModType,in_modgroup: ModGroup) {
+
+        let mut dbt = self.statusdb.write().await;
+         
+        let (_,statusvector) = dbt.entry(in_module.clone()).or_insert((in_modgroup.clone(),Vec::new()));
+
+        if !statusvector.contains(&StatusType::Enabled(StatusLvl::Instance)) && !statusvector.contains(&StatusType::Disabled(StatusLvl::Instance))
+        {
+            match in_modgroup {
+                ModGroup::Core => statusvector.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
+                ModGroup::Custom => statusvector.push(StatusType::Disabled(StatusLvl::Instance)),
+            }
+        }
+
+    }
+
     async fn int_add_botaction(&self, in_module: ModType, in_modgroup: ModGroup, in_action: BotAction) {
         botlog::trace(
             "Add botaction called",
@@ -373,17 +461,19 @@ impl ModulesManager {
             )
         }
 
-        let mut dbt = self.statusdb.write().await;
-        // 
-        let statusvector = dbt.entry(in_module.clone()).or_insert((in_modgroup.clone(),Vec::new()));
+        // let mut dbt = self.statusdb.write().await;
+        // // 
+        // let statusvector = dbt.entry(in_module.clone()).or_insert((in_modgroup.clone(),Vec::new()));
 
-        match in_modgroup {
-            ModGroup::Core => statusvector.1.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
-            ModGroup::Custom => statusvector.1.push(StatusType::Disabled(StatusLvl::Instance)),
-        }
+        // match in_modgroup {
+        //     ModGroup::Core => statusvector.1.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
+        //     ModGroup::Custom => statusvector.1.push(StatusType::Disabled(StatusLvl::Instance)),
+        // }
 
         // statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level
 
+        self.affirm_in_statusdb(in_module.clone(),in_modgroup).await;
+
         let mut a = self.botactions.write().await;
         let modactions = a.entry(in_module.clone()).or_insert(Vec::new());
 

From 23f12b395624d70d421fe9d6e6eb749d3e616054 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 09:37:08 -0400
Subject: [PATCH 11/98] smol

---
 src/core/botmodules.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 78db77e..6332ab6 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -25,7 +25,7 @@ use std::collections::HashMap;
 // use std::error::Error;
 use std::sync::Arc;
 
-use futures::stream::iter;
+// use futures::stream::iter;
 use twitch_irc::message::PrivmsgMessage;
 
 use tokio::sync::RwLock;
@@ -328,7 +328,7 @@ impl ModulesManager {
 
                 (
                     StatusType::Disabled(StatusLvl::Instance),
-                    ChangeResult::Success("Disabled at Instance".to_string())
+                    ChangeResult::Success("Forced Disabled".to_string())
                 )
             },
         }

From 619cdd192390940c7b34712215e22370d1af9c23 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 12:21:00 -0400
Subject: [PATCH 12/98] complete helper fns

---
 src/core/botmodules.rs | 191 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 182 insertions(+), 9 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 6332ab6..1bffc07 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -231,7 +231,7 @@ impl ModulesManager {
         mgrarc
     }
 
-    pub fn modstatus(&self, _: ModType, _: ChType) -> StatusType {
+    pub async fn modstatus(&self, in_module: ModType, in_chnl: ChType) -> StatusType {
         // Example usage : botmanager.modstatus(
         //     BotModule("GambaCore"),
         //     Channel("modulatingforce")
@@ -239,7 +239,84 @@ impl ModulesManager {
         // - The ModStatusType checks in the context of the given channel ,
         //  but also validates based on wheher the module is disabled at a bot instance
         //  level as well
-        StatusType::Enabled(StatusLvl::Instance)
+
+        let dbt = self.statusdb.read().await;
+         
+        // let a = dbt.entry(in_module.clone()).;
+        let (mgrp,statusvector) = dbt.get(&in_module).unwrap();
+
+        match mgrp {
+            ModGroup::Core => {
+                    StatusType::Enabled(StatusLvl::Instance)  // This forces core to be validated as Enabled, even if undesired scenario of missing StatusLvl::Instance or empty vectors
+            },
+            ModGroup::Custom  => {
+                // // remove all instance level pattern for the module
+                // while let Some(index) = statusvector
+                //         .iter()
+                //         .position(|x| (*x == StatusType::Enabled(StatusLvl::Instance)) || (*x == StatusType::Disabled(StatusLvl::Instance))) {
+
+                //             statusvector.remove(index);
+                //         }
+                // statusvector.push(StatusType::Disabled(StatusLvl::Instance));
+
+                // (
+                //     StatusType::Disabled(StatusLvl::Instance),
+                //     ChangeResult::Success("Set Disabled at Instance".to_string())
+                // )
+
+                /* 
+                
+                [x] 1. If Disabled at Instance Level , 
+                      [x] a. And Enabled at a Channel Level > return Enabled(Channel)
+                      [x] b. And Disabled at a Channel Level > return Disabled(Channel)
+                      [x] c. And Not Defined at Channel Level > return Disabled(Instance)
+                [x] 2. If Enabled at Instance Level , 
+                      [x] a. And Enabled at a Channel Level > return Enabled(Channel)
+                      [x] b. And Disabled at a Channel Level > return Disabled(Channel)
+                      [x] c. And Not Defined at Channel Level > return Enabled(Instance)
+                */
+
+
+
+                if statusvector.contains(&StatusType::Disabled(StatusLvl::Instance)) {
+                    // [x] 1. If Disabled at Instance Level , 
+
+
+                    if statusvector.contains(&StatusType::Enabled(StatusLvl::Ch(in_chnl.clone()))) { 
+                    // [x] a. And Enabled at a Channel Level > return Enabled(Channel)
+                        StatusType::Enabled(StatusLvl::Ch(in_chnl.clone())) 
+                    } else if statusvector.contains(&StatusType::Disabled(StatusLvl::Ch(in_chnl.clone()))) { 
+                    // [x] b. And Disabled at a Channel Level > return Disabled(Channel)
+                        StatusType::Disabled(StatusLvl::Ch(in_chnl.clone()))
+                    } else {
+                    // [x] c. And Not Defined at Channel Level > return Disabled(Instance)
+                        StatusType::Disabled(StatusLvl::Instance)
+                    }
+
+                } else if statusvector.contains(&StatusType::Enabled(StatusLvl::Instance)) {
+                    // [x] 2. If Enabled at Instance Level , 
+
+                    if statusvector.contains(&StatusType::Enabled(StatusLvl::Ch(in_chnl.clone()))) { 
+                    // [x] a. And Enabled at a Channel Level > return Enabled(Channel)
+                        StatusType::Enabled(StatusLvl::Ch(in_chnl.clone())) 
+                    } else if statusvector.contains(&StatusType::Disabled(StatusLvl::Ch(in_chnl.clone()))) {
+                    // [x] b. And Disabled at a Channel Level > return Disabled(Channel)
+                        StatusType::Disabled(StatusLvl::Ch(in_chnl.clone()))
+                    } else {
+                    // [x] c. And Not Defined at Channel Level > return Enabled(Instance)
+                        StatusType::Enabled(StatusLvl::Instance)
+                    }
+
+                } else {
+                    // ? In some unexpected scenario (e.g., not define at instance level), assume Disabled at Instance level and set as this way
+                    self.set_instance_disabled(in_module).await;
+                    StatusType::Disabled(StatusLvl::Instance)
+                }
+            },
+        }
+        
+
+        //StatusType::Enabled(StatusLvl::Instance)
     }
 
     // pub fn togglestatus(&self, _: ModType, _: ChType) -> StatusType {
@@ -283,7 +360,7 @@ impl ModulesManager {
 
                 (
                     StatusType::Disabled(StatusLvl::Instance),
-                    ChangeResult::Success("Disabled at Instance".to_string())
+                    ChangeResult::Success("Set Disabled at Instance".to_string())
                 )
             },
         }
@@ -336,22 +413,118 @@ impl ModulesManager {
         // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub fn set_instance_enabled(&self, _in_module: ModType) -> (StatusType,ChangeResult) {
+    pub async fn set_instance_enabled(&self, in_module: ModType) -> (StatusType,ChangeResult) {
         // at Instance level
         //  - If core module, do nothing
-        (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+
+        let mut dbt = self.statusdb.write().await;
+         
+        // let a = dbt.entry(in_module.clone()).;
+        let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
+
+        match mgrp {
+            ModGroup::Core => {
+                (
+                    StatusType::Enabled(StatusLvl::Instance),
+                    ChangeResult::NoChange("Core Modules are always Enabled".to_string())
+                )
+            },
+            ModGroup::Custom  => {
+                // remove all instance level pattern for the module
+                while let Some(index) = statusvector
+                        .iter()
+                        .position(|x| (*x == StatusType::Enabled(StatusLvl::Instance)) || (*x == StatusType::Disabled(StatusLvl::Instance))) {
+
+                            statusvector.remove(index);
+                        }
+                statusvector.push(StatusType::Enabled(StatusLvl::Instance));
+
+                (
+                    StatusType::Enabled(StatusLvl::Instance),
+                    ChangeResult::Success("Set Enabled at Instance".to_string())
+                )
+            },
+        }
+
+        // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub fn set_ch_disabled(&self, _in_module: ModType , _in_chnl: ChType) -> (StatusType,ChangeResult) {
+    pub async fn set_ch_disabled(&self, in_module: ModType , in_chnl: ChType) -> (StatusType,ChangeResult) {
         // at Instance level
         //  - If core module, do nothing
-        (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+
+
+        let mut dbt = self.statusdb.write().await;
+         
+        // let a = dbt.entry(in_module.clone()).;
+        let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
+
+        match mgrp {
+            ModGroup::Core => {
+                (
+                    StatusType::Enabled(StatusLvl::Instance),
+                    ChangeResult::Failed("Core Modules cannot be disabled".to_string())
+                )
+            },
+            ModGroup::Custom  => {
+                // remove all channel level pattern for the module
+                while let Some(index) = statusvector
+                        .iter()
+                        .position(|x| 
+                            (*x == StatusType::Enabled(StatusLvl::Ch(in_chnl.clone()))) || (*x == StatusType::Disabled(StatusLvl::Ch(in_chnl.clone())))) 
+                        {
+
+                            statusvector.remove(index);
+                        }
+                statusvector.push(StatusType::Disabled(StatusLvl::Ch(in_chnl.clone())));
+
+                (
+                    StatusType::Disabled(StatusLvl::Ch(in_chnl.clone())),
+                    ChangeResult::Success("Set Disabled at Channel Level".to_string())
+                )
+            },
+        }
+
+        // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub fn set_ch_enabled(&self, _in_module: ModType , _in_chnl: ChType) -> (StatusType,ChangeResult) {
+    pub async fn set_ch_enabled(&self, in_module: ModType , in_chnl: ChType) -> (StatusType,ChangeResult) {
         // at Instance level
         //  - If core module, do nothing
-        (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
+
+        let mut dbt = self.statusdb.write().await;
+         
+        // let a = dbt.entry(in_module.clone()).;
+        let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
+
+        match mgrp {
+            ModGroup::Core => {
+                (
+                    StatusType::Enabled(StatusLvl::Instance),
+                    ChangeResult::NoChange("Core Modules are always Enabled".to_string())
+                )
+            },
+            ModGroup::Custom  => {
+                // remove all channel level pattern for the module
+                while let Some(index) = statusvector
+                        .iter()
+                        .position(|x| 
+                            (*x == StatusType::Enabled(StatusLvl::Ch(in_chnl.clone()))) || (*x == StatusType::Disabled(StatusLvl::Ch(in_chnl.clone())))) 
+                        {
+
+                            statusvector.remove(index);
+                        }
+                statusvector.push(StatusType::Enabled(StatusLvl::Ch(in_chnl.clone())));
+
+                (
+                    StatusType::Enabled(StatusLvl::Ch(in_chnl.clone())),
+                    ChangeResult::Success("Set Enabled at Channel Level".to_string())
+                )
+            },
+        }
+
+
+        // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
 

From 68f9be496887377e951147c302b128f8cc595801 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 14:01:54 -0400
Subject: [PATCH 13/98] unit tests

---
 src/core/botmodules.rs | 257 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 257 insertions(+)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 1bffc07..fadfdab 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -28,6 +28,8 @@ use std::sync::Arc;
 // use futures::stream::iter;
 use twitch_irc::message::PrivmsgMessage;
 
+// use casual_logger::Log;
+
 use tokio::sync::RwLock;
 
 use async_trait::async_trait;
@@ -672,3 +674,258 @@ impl ModulesManager {
         // Passing None to chnl may be a heavy operation, as this will review and look at the whole table
     }
 }
+
+
+// =====================
+// =====================
+// =====================
+// =====================
+// =====================
+
+#[cfg(test)]
+mod core_modulesmanager {
+
+
+    use casual_logger::Log;
+    use casual_logger::Extension;
+
+    use super::*;
+
+
+    /*
+        Possible Tests
+
+        [x] Test 1 - Custom ModGroup Workflow
+        1. affirm_in_statusdb(Experiments01,Custom)
+        2. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        3. set_instance_enabled(Experiments01) 
+        4. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        5. set_ch_disabled(Experiments01,TestChannel01)
+        6. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        7. set_ch_enabled(Experiments01,TestChannel01) & set_ch_disabled(Experiments01,TestChannel02)
+        8. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        9. set_instance_disabled(Experiments01)
+        10. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        11. force_disable(Experiments01)
+        12. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+
+
+        [x] Test 2 - Core ModGroup Workflow
+        1. affirm_in_statusdb(CoreModule01,Core)
+        2. modstatus(CoreModule01,TestChannel01) & modstatus(CoreModule01,TestChannel02)
+        3. set_instance_enabled(CoreModule01)
+        4. modstatus(CoreModule01,TestChannel01) & modstatus(CoreModule01,TestChannel02)
+        5. set_ch_disabled(CoreModule01,TestChannel01)
+        6. modstatus(CoreModule01,TestChannel01)  & modstatus(CoreModule01,TestChannel02)
+        7. set_ch_enabled(CoreModule01,TestChannel01) & set_ch_disabled(CoreModule01,TestChannel02)
+        8. modstatus(CoreModule01,TestChannel01)  & modstatus(CoreModule01,TestChannel02)
+        9. set_instance_disabled(CoreModule01)
+        10. modstatus(CoreModule01,TestChannel01) & modstatus(CoreModule01,TestChannel02)
+        11. force_disable(CoreModule01)
+        12. modstatus(CoreModule01,TestChannel01) & modstatus(CoreModule01,TestChannel02)
+
+
+     */
+
+    async fn complex_workflow(
+        in_module: ModType , 
+        in_modgroup : ModGroup , 
+        in_chnl1 : ChType, 
+        in_chnl2 : ChType) 
+    {
+
+        
+        let mgr = ModulesManager::init().await;
+
+        /*
+        1. affirm_in_statusdb(Experiments01,Custom)
+        2. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+         */
+
+         mgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
+
+        match in_modgroup {
+            ModGroup::Custom => {
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Disabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Disabled(StatusLvl::Instance));
+            },
+            ModGroup::Core => {                
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+        }
+
+ 
+         /*
+         3. set_instance_enabled(Experiments01) 
+         4. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+          */
+         mgr.set_instance_enabled(in_module.clone()).await;
+         
+         match in_modgroup {
+            ModGroup::Custom => {
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+            ModGroup::Core => {                
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+        }
+ 
+         /*
+         5. set_ch_disabled(Experiments01,TestChannel01)
+         6. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+          */
+ 
+          mgr.set_ch_disabled(in_module.clone(),in_chnl1.clone()).await;
+ 
+          //StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
+         
+          match in_modgroup {
+            ModGroup::Custom => {
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone())));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+            ModGroup::Core => {                
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+        }
+ 
+ 
+          /*
+         7. set_ch_enabled(Experiments01,TestChannel01) & set_ch_disabled(Experiments01,TestChannel02)
+         8. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+           */
+ 
+         mgr.set_ch_enabled(in_module.clone(),in_chnl1.clone()).await;
+
+         //StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
+         
+         match in_modgroup {
+            ModGroup::Custom => {
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Ch(in_chnl1.clone())));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+            ModGroup::Core => {                
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+        }
+ 
+         /*
+         9. set_instance_disabled(Experiments01)
+         10. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+          */
+ 
+          mgr.set_instance_disabled(in_module.clone()).await;
+          
+          // StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
+         
+          match in_modgroup {
+            ModGroup::Custom => {
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Ch(in_chnl1.clone())));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Disabled(StatusLvl::Instance));
+            },
+            ModGroup::Core => {                
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+        }
+          /*
+         11. force_disable(Experiments01)
+         12. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+           */
+ 
+           mgr.force_disable(in_module.clone()).await;
+         
+           match in_modgroup {
+            ModGroup::Custom => {
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Disabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Disabled(StatusLvl::Instance));
+            },
+            ModGroup::Core => {                
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl1.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+                assert_eq!(mgr.modstatus(in_module.clone(), in_chnl2.clone()).await,
+                StatusType::Enabled(StatusLvl::Instance));
+            },
+        }
+
+    }
+
+
+     #[tokio::test]
+     async fn custom_modgroup_workflow() {
+        Log::set_file_ext(Extension::Log);
+
+        /*
+        
+        
+        [x] Test 1 - Custom ModGroup Workflow
+        1. affirm_in_statusdb(Experiments01,Custom)
+        2. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        3. set_instance_enabled(Experiments01) 
+        4. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        5. set_ch_disabled(Experiments01,TestChannel01)
+        6. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        7. set_ch_enabled(Experiments01,TestChannel01) & set_ch_disabled(Experiments01,TestChannel02)
+        8. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        9. set_instance_disabled(Experiments01)
+        10. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+        11. force_disable(Experiments01)
+        12. modstatus(Experiments01,TestChannel01) & modstatus(Experiments01,TestChannel02)
+
+         */
+
+        let in_module = BotModule("Experiments01".to_string());
+        let in_modgroup = ModGroup::Custom;
+        let (in_chnl1,in_chnl2) = 
+            (ChType::Channel("TestChannel01".to_string()),ChType::Channel("TestChannel02".to_string()));
+
+        complex_workflow(in_module, in_modgroup, in_chnl1, in_chnl2).await;
+
+
+     }
+
+
+     #[tokio::test]
+     async fn core_modgroup_workflow() {
+        Log::set_file_ext(Extension::Log);
+    
+
+        let in_module = BotModule("CoreModule01".to_string());
+        let in_modgroup = ModGroup::Core;
+        let (in_chnl1,in_chnl2) = 
+            (ChType::Channel("TestChannel01".to_string()),ChType::Channel("TestChannel02".to_string()));
+
+        complex_workflow(in_module, in_modgroup, in_chnl1, in_chnl2).await;
+
+
+    }
+
+
+}

From 2cf44bb6ca28be318fb726a5b94e00b8f597d06f Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Thu, 21 Mar 2024 21:20:16 -0400
Subject: [PATCH 14/98] (init) modulesmgr commands

---
 src/core/botmodules.rs | 314 ++++++++++++++++++++++++++++++++++++++++-
 src/core/identity.rs   |   2 +-
 2 files changed, 314 insertions(+), 2 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index fadfdab..fb57dfc 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -35,17 +35,132 @@ use tokio::sync::RwLock;
 use async_trait::async_trait;
 
 use self::bot_actions::actions_util::BotAR;
+use crate::core::bot_actions::actions_util;
 use crate::core::botinstance::{BotInstance, ChType,ChangeResult};
 use crate::core::botlog;
-use crate::core::identity;
+use crate::core::identity::{self, Permissible};
 
 use crate::core::bot_actions;
 pub use ChType::Channel;
 pub use ModType::BotModule;
 
+use super::identity::ChatBadge;
+
 // use super::identity::ChangeResult;
 
 
+pub async fn init(mgr: Arc<ModulesManager>) {
+
+    const OF_CMD_CHANNEL:ChType = Channel(String::new());
+
+    // 1. Define the BotAction
+    let botc1 = BotCommand {
+        module: BotModule(String::from("core")),
+        command: String::from("enable"), // command call name
+        alias: vec![
+            String::from("e"), 
+            String::from("en")], // String of alternative names
+        exec_body: actions_util::asyncbox(cmd_enable),
+        help: String::from("Test Command tester"),
+        required_roles: vec![
+            identity::UserRole::BotAdmin,
+            identity::UserRole::Mod(OF_CMD_CHANNEL),
+            identity::UserRole::SupMod(OF_CMD_CHANNEL),
+            identity::UserRole::Broadcaster,
+        ], 
+    };
+
+    // 2. Add the BotAction to ModulesManager
+    botc1.add_core_to_modmgr(Arc::clone(&mgr)).await;
+    
+    async fn cmd_enable(bot: BotAR, msg: PrivmsgMessage) {
+        /*
+            There should be additional validation checks
+            - BotAdmins can only run instance level (-i) enables
+            - If BotAdmins need to enable/disable at instance level, they must Promote themselves to be a Mod at least
+            - Other Special Roles (Mod,SupMod,Broadcaster) can run without issues to enable the module at Channel Level
+         */
+
+        /*
+            enable -i <module> // enables at Instance
+            enable <module> // enables at Channel
+         */
+
+        /*
+
+            1. Parse out Message Arguments
+
+            
+            exec_enable()
+
+            2. Get Special Roles of CmdSender
+            3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster) 
+                3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
+                3b. , and is -i (to instance) , return a Success
+            4. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+                4a. , and is not -i (to instance) , return a Success
+                4b. , and is -i (to instance) , return a Failure they are not allowed
+            5. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+                5a. , and is not -i (to instance) , return a Success
+                5b. , and is -i (to instance) , return a Success
+
+         */
+
+
+        /*
+        exec_enable(Self,requestor,requestor_badge,trg_module,Channel) -> ChangeResult
+        */
+
+
+    }
+
+
+
+    // 1. Define the BotAction
+    let botc1 = BotCommand {
+        module: BotModule(String::from("core")),
+        command: String::from("disable"), // command call name
+        alias: vec![
+            String::from("d")], // String of alternative names
+        exec_body: actions_util::asyncbox(cmd_disable),
+        help: String::from("Test Command tester"),
+        required_roles: vec![
+            identity::UserRole::BotAdmin,
+            identity::UserRole::Mod(OF_CMD_CHANNEL),
+            identity::UserRole::SupMod(OF_CMD_CHANNEL),
+            identity::UserRole::Broadcaster,
+        ], 
+    };
+
+    // 2. Add the BotAction to ModulesManager
+    botc1.add_core_to_modmgr(Arc::clone(&mgr)).await;
+    
+    async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) {
+        /*
+            There should be additional validation checks
+            - BotAdmins can only run instance level (-i) disables
+            - If BotAdmins need to enable/disable at instance level, they must Promote themselves to be a Mod at least
+            - Other Special Roles (Mod,SupMod,Broadcaster) can run without issues to disable the module at Channel Level
+            */
+
+        /*
+            disable -i <module> // disables at Instance
+            disable <module> // disables at Channel
+            disable -f <module> // force disables (instance and enabled are removed)
+         */
+
+
+    }
+
+
+}
+
+
+
+
+
+
+
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum ModType {
     BotModule(String),
@@ -332,6 +447,203 @@ impl ModulesManager {
     //     Ok("")
     // }
 
+        /*
+        exec_enable(self,requestor,requestor_badge,trg_module,Channel) -> ChangeResult
+        */
+
+    pub async fn exec_enable(
+        &self,
+        requestor: String,
+        requestor_badge: Option<ChatBadge>,
+        trg_module: ModType,
+        // channel: Option<ChType>,
+        trg_level: StatusLvl,
+        bot: BotAR,
+    ) -> ChangeResult 
+    {
+
+        /*
+        
+            1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+            1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                1a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
+                1b. , and is -i (to instance) , return a Success
+            
+            2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+            2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                2a. , and is not -i (to instance) , return a Success
+                2b. , and is -i (to instance) ,  return a Failure they are not allowed
+
+            3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+            3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
+                3a. , and is not -i (to instance) , return a Success
+                3b. , and is -i (to instance) , return a Success    
+         */
+
+
+         /*
+            [ ] 1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+                1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                    1a. , and is -i (to instance) , return a Success
+                    1b. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
+
+            
+          */
+
+
+        let botlock = bot.read().await;
+        let id = botlock.get_identity();
+        let mut idlock = id.write().await;
+
+        // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
+
+        let arb_chnl = match trg_level.clone() {
+            StatusLvl::Instance => ChType::Channel(requestor.to_lowercase()),
+            StatusLvl::Ch(a) => a,
+        };
+
+        const OF_CMD_CHANNEL:ChType = Channel(String::new());
+        
+        let (admin_level_access,_) = idlock.can_user_run(requestor.clone(), arb_chnl.clone(), requestor_badge.clone(), 
+        vec![
+            identity::UserRole::BotAdmin,
+        ]).await;
+
+
+        let (chnl_elevated_access,_) = idlock.can_user_run(requestor, arb_chnl, requestor_badge.clone(), 
+        vec![
+            identity::UserRole::Mod(OF_CMD_CHANNEL),
+            identity::UserRole::SupMod(OF_CMD_CHANNEL),
+            identity::UserRole::Broadcaster,
+        ]).await;
+
+        if let Permissible::Allow = admin_level_access {
+            if let Permissible::Block = chnl_elevated_access {
+                match trg_level {
+                    StatusLvl::Instance => {
+                        self.set_instance_enabled(trg_module.clone()).await;
+                        ChangeResult::Success("Enabled at Instance Level".to_string())
+                    },
+                    StatusLvl::Ch(_) => {
+                        ChangeResult::Failed("Promote yourself Temporarily First".to_string())
+                    },
+                };
+            }
+        }
+
+
+        /*
+            [ ] 2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+                2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                    2a. , and is -i (to instance) ,  return a Failure they are not allowed
+                    2b. , and is not -i (to instance) , return a Success
+
+         */
+
+        if let Permissible::Block = admin_level_access {
+            if let Permissible::Allow = chnl_elevated_access {
+                match trg_level.clone() {
+                    StatusLvl::Instance => {
+                        ChangeResult::Failed("You're not allowed".to_string())
+                    },
+                    StatusLvl::Ch(in_chnl) => {
+                        self.set_ch_enabled(trg_module.clone(), in_chnl).await;
+                        ChangeResult::Success("Enabled at Channel Level".to_string())
+                    },
+                };
+            }
+        }
+
+
+        /*
+        
+            [ ] 3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+                3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
+                    3a. , and is not -i (to instance) , return a Success
+                    3b. , and is -i (to instance) , return a Success    
+         */
+
+
+         if let Permissible::Allow = admin_level_access {
+            if let Permissible::Allow = chnl_elevated_access {
+                match trg_level {
+                    StatusLvl::Instance => {
+                        self.set_instance_enabled(trg_module.clone()).await;
+                        ChangeResult::Success("Enabled at Instance Level".to_string())
+                    },
+                    StatusLvl::Ch(in_chnl) => {
+                        self.set_ch_enabled(trg_module.clone(), in_chnl).await;
+                        ChangeResult::Success("Enabled at Channel Level".to_string())
+                    },
+                };
+            }
+        }
+
+
+
+
+        // =======================
+
+        // =======================
+
+        // =======================
+
+
+        // /*
+        
+        //     2. Get Special Roles of CmdSender
+        //     3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster) 
+        //         3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
+        //         3b. , and is -i (to instance) , return a Success
+        //     4. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+        //         4a. , and is not -i (to instance) , return a Success
+        //         4b. , and is -i (to instance) , return a Failure they are not allowed
+        //     5. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+        //         5a. , and is not -i (to instance) , return a Success
+        //         5b. , and is -i (to instance) , return a Success
+
+        
+        // */
+
+        // // [ ] 2. Get Special Roles of CmdSender
+
+        // let botlock = bot.read().await;
+        // let id = botlock.get_identity();
+        // let idlock = id.read().await;
+
+
+        // let trgchnl = {
+        //     match trg_level {
+        //         StatusLvl::Instance => None,
+        //         StatusLvl::Ch(a) => Some(a),
+        //     }
+        // };
+
+        // let requestor_roles = idlock
+        //         .getspecialuserroles(
+        //             requestor.to_lowercase(),
+        //             trgchnl,
+        //         )
+        //         .await;
+
+        // /*
+        //     [ ] 3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster) 
+        //         3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
+        //         3b. , and is -i (to instance) , return a Success
+        //  */
+        
+        // if requestor_roles.contains(&identity::UserRole::BotAdmin) 
+        //     && !requestor_roles.contains(&identity::UserRole::Broadcaster)
+        //     && !requestor_roles.contains(&identity::UserRole::Mod(trgchnl)) 
+        // {
+
+        // } 
+
+
+
+        ChangeResult::NoChange("ERROR : Not implemented yet".to_string())
+    }
+
     pub async fn set_instance_disabled(&self, in_module: ModType) -> (StatusType,ChangeResult) {
         // at Instance level
         // - If core module, do nothing
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 65a5088..84905cc 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -602,7 +602,7 @@ pub struct IdentityManager {
         >
 */
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum ChatBadge {
     Broadcaster,
     Mod,

From 0d6cc132ea6e5ff73745fa240767e628178823ad Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 08:21:10 -0400
Subject: [PATCH 15/98] (cont) enable/disable logic

---
 src/core/botmodules.rs | 308 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 301 insertions(+), 7 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index fb57dfc..568683a 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -77,7 +77,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         /*
             There should be additional validation checks
             - BotAdmins can only run instance level (-i) enables
-            - If BotAdmins need to enable/disable at instance level, they must Promote themselves to be a Mod at least
+            - If BotAdmins need to enable/disable at Channel level, they must Promote themselves to be a Mod at least
             - Other Special Roles (Mod,SupMod,Broadcaster) can run without issues to enable the module at Channel Level
          */
 
@@ -107,11 +107,102 @@ pub async fn init(mgr: Arc<ModulesManager>) {
          */
 
 
-        /*
-        exec_enable(Self,requestor,requestor_badge,trg_module,Channel) -> ChangeResult
+
+        // [ ] Unwraps arguments from message
+
+        let (arg1, arg2) = {
+
+            let mut argv = msg.message_text.split(' ');
+
+            argv.next(); // Skip the command name
+
+            let arg1 = argv.next();
+
+            let arg2 = argv.next();
+
+            (arg1, arg2)
+        };
+
+
+        /* -- Related function to call later
+        exec_enable(
+                &self,
+                requestor: String,
+                requestor_badge: Option<ChatBadge>,
+                trg_module: ModType,
+                // channel: Option<ChType>,
+                trg_level: StatusLvl,
+                bot: BotAR,
+            ) -> ChangeResult 
         */
 
 
+        // [ ] requestor: String,
+        let requester = msg.clone().sender.name;
+
+
+        // [ ] requestor_badge: Option<ChatBadge>,
+
+        let mut requestor_badge_mut: Option<ChatBadge> = None;
+
+        for b in &msg.badges {
+            if b.name == "moderator" {
+                requestor_badge_mut = Some(ChatBadge::Mod);
+            } else if b.name == "broadcaster" {
+                requestor_badge_mut = Some(ChatBadge::Broadcaster);
+            }
+        }
+
+        let requestor_badge = requestor_badge_mut;
+
+
+        // [ ] trg_module: ModType,
+        //      - [ ] Need to validate an actual ModType - otherwise, fail or exit the cmd
+    
+        let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
+
+        if let Some(trg_module_str) = trg_module {
+
+            let botlock = bot.read().await;
+            let modmgr = Arc::clone(&botlock.botmodules);
+            let modlist = modmgr.moduleslist().await;
+            let rslt =  modlist.get(&ModType::BotModule(trg_module_str.to_string()));
+
+            if let None = rslt {
+
+                let outmsg = "uuh module doesn't exist";
+
+                botlog::debug(
+                    outmsg,
+                    Some("botmodules.rs > cmd_enable()".to_string()),
+                    Some(&msg),
+                );
+        
+                botlock
+                    .botmgrs
+                    .chat
+                    .say_in_reply_to(&msg, outmsg.to_string())
+                    .await;
+
+                return;
+            }
+
+        }
+        
+
+        // [ ] trg_level: StatusLvl,
+
+        let currchnl = msg.channel_login.to_lowercase();
+
+        let trg_level = 
+            if arg1 == Some("-i") { StatusLvl::Instance } 
+            else if arg1 == Some("-f") { StatusLvl::Instance }
+            else { StatusLvl::Ch(ChType::Channel(currchnl)) }
+            ; 
+
+
+
+
     }
 
 
@@ -138,10 +229,10 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) {
         /*
             There should be additional validation checks
-            - BotAdmins can only run instance level (-i) disables
-            - If BotAdmins need to enable/disable at instance level, they must Promote themselves to be a Mod at least
+            - BotAdmins can only run instance level (-i) disables and (-f) force disable
+            - If BotAdmins need to enable/disable at Channel level, they must Promote themselves to be a Mod at least
             - Other Special Roles (Mod,SupMod,Broadcaster) can run without issues to disable the module at Channel Level
-            */
+        */
 
         /*
             disable -i <module> // disables at Instance
@@ -149,6 +240,26 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             disable -f <module> // force disables (instance and enabled are removed)
          */
 
+         /*
+        
+            1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+            1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                1a. , and has no special flags (-i / -f) , return a Failure recommending BotAdmin promote themselves first
+                1b. , and is -i (to instance) , return a Success
+                1c. , and is -f (forced) , return a Success
+            
+            2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+            2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                2a. , and has no special flags (-i / -f) , return a Success
+                2b. , and is -i (to instance) ,  return a Failure they are not allowed
+                2c. , and is -f (forced) ,  return a Failure they are not allowed
+
+            3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+            3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
+                3a. , and has no special flags (-i / -f) , return a Success
+                3b. , and is -i (to instance) , return a Success
+                3c. , and is -f (forced) , return a Success    
+         */
 
     }
 
@@ -348,6 +459,24 @@ impl ModulesManager {
         mgrarc
     }
 
+
+    pub async fn moduleslist(&self) -> HashMap<ModType,ModGroup>
+    {
+
+        // let db = Arc::clone(&self.statusdb);
+        let db = self.statusdb.clone();
+        let dblock = db.read().await;
+
+        let mut outmap = HashMap::new();
+
+        for (k,v) in &(*dblock) {
+            let (mgrp,_) = v;
+            let mtype = k;
+            outmap.insert((*mtype).clone(), (*mgrp).clone());
+        }
+        outmap
+    }
+
     pub async fn modstatus(&self, in_module: ModType, in_chnl: ChType) -> StatusType {
         // Example usage : botmanager.modstatus(
         //     BotModule("GambaCore"),
@@ -641,7 +770,161 @@ impl ModulesManager {
 
 
 
-        ChangeResult::NoChange("ERROR : Not implemented yet".to_string())
+        ChangeResult::Failed("ERROR : Not implemented yet".to_string())
+    }
+
+
+    pub async fn exec_disable(
+        &self,
+        requestor: String,
+        requestor_badge: Option<ChatBadge>,
+        trg_module: ModType,
+        // channel: Option<ChType>,
+        trg_level: StatusLvl,
+        force: bool,
+        bot: BotAR,
+    ) -> ChangeResult 
+    {
+
+        /*
+        
+            1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+            1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                1a. , and has no special flags (-i / -f) , return a Failure recommending BotAdmin promote themselves first
+                1b. , and is -i (to instance) , return a Success
+                1c. , and is -f (forced) , return a Success
+            
+            2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+            2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                2a. , and has no special flags (-i / -f) , return a Success
+                2b. , and is -i (to instance) ,  return a Failure they are not allowed
+                2c. , and is -f (forced) ,  return a Failure they are not allowed
+
+            3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+            3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
+                3a. , and has no special flags (-i / -f) , return a Success
+                3b. , and is -i (to instance) , return a Success
+                3c. , and is -f (forced) , return a Success    
+         */
+
+         
+
+        let botlock = bot.read().await;
+        let id = botlock.get_identity();
+        let mut idlock = id.write().await;
+
+        // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
+
+        let arb_chnl = match trg_level.clone() {
+            StatusLvl::Instance => ChType::Channel(requestor.to_lowercase()),
+            StatusLvl::Ch(a) => a,
+        };
+
+        const OF_CMD_CHANNEL:ChType = Channel(String::new());
+        
+        let (admin_level_access,_) = idlock.can_user_run(requestor.clone(), arb_chnl.clone(), requestor_badge.clone(), 
+        vec![
+            identity::UserRole::BotAdmin,
+        ]).await;
+
+
+        let (chnl_elevated_access,_) = idlock.can_user_run(requestor, arb_chnl, requestor_badge.clone(), 
+        vec![
+            identity::UserRole::Mod(OF_CMD_CHANNEL),
+            identity::UserRole::SupMod(OF_CMD_CHANNEL),
+            identity::UserRole::Broadcaster,
+        ]).await;
+
+
+        /*
+        
+            [ ] 1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+                1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                    1a. , and is -f (forced) , return a Success
+                    1b. , and is -i (to instance) , return a Success
+                    1c. , and has no special flags (-i / -f) , return a Failure recommending BotAdmin promote themselves first
+            
+         */
+
+        if let Permissible::Allow = admin_level_access {
+            if let Permissible::Block = chnl_elevated_access {
+                if force {
+                    self.force_disable(trg_module.clone()).await;
+                    return ChangeResult::Success("Forced Disable".to_string());
+                } else {
+                    match trg_level {
+                        StatusLvl::Instance => {
+                            self.set_instance_disabled(trg_module.clone()).await;
+                            ChangeResult::Success("Disabled at Instance Level".to_string())
+                        },
+                        StatusLvl::Ch(_) => {
+                            ChangeResult::Failed("Promote yourself Temporarily First".to_string())
+                        },
+                    };
+                }
+            }
+        }
+
+
+        /*
+                [ ] 2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+                    2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                        2a. , and is -f (forced) ,  return a Failure they are not allowed
+                        2b. , and is -i (to instance) ,  return a Failure they are not allowed
+                        2c. , and has no special flags (-i / -f) , return a Success
+
+         */
+
+         if let Permissible::Block = admin_level_access {
+            if let Permissible::Allow = chnl_elevated_access {
+                if force {
+                    return ChangeResult::Failed("You're not allowed".to_string());
+                } else {
+                    match trg_level.clone() {
+                        StatusLvl::Instance => {
+                            ChangeResult::Failed("You're not allowed".to_string())
+                        },
+                        StatusLvl::Ch(in_chnl) => {
+                            self.set_ch_disabled(trg_module.clone(), in_chnl).await;
+                            ChangeResult::Success("Disabled at Channel Level".to_string())
+                        },
+                    };
+                }
+            }
+        }
+
+
+        /*
+                [ ] 3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+                    3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
+                        3a. , and is -f (forced) , return a Success   
+                        3b. , and is -i (to instance) , return a Success
+                        3c. , and has no special flags (-i / -f) , return a Success
+
+         */
+
+         if let Permissible::Allow = admin_level_access {
+            if let Permissible::Allow = chnl_elevated_access {
+                if force {
+                    self.force_disable(trg_module.clone()).await;
+                    return ChangeResult::Success("Forced Disable".to_string());
+                } else {
+                    match trg_level {
+                        StatusLvl::Instance => {
+                            self.set_instance_disabled(trg_module.clone()).await;
+                            ChangeResult::Success("Disabled at Instance Level".to_string())
+                        },
+                        StatusLvl::Ch(in_chnl) => {
+                            self.set_ch_disabled(trg_module.clone(), in_chnl).await;
+                            ChangeResult::Success("Disabled at Channel Level".to_string())
+                        },
+                    };
+                }
+            }
+        }
+
+
+         ChangeResult::Failed("ERROR : Not implemented yet".to_string())
     }
 
     pub async fn set_instance_disabled(&self, in_module: ModType) -> (StatusType,ChangeResult) {
@@ -1003,6 +1286,17 @@ mod core_modulesmanager {
 
     use super::*;
 
+    #[test]
+    fn WIP_case_insensitive_test() {
+        Log::set_file_ext(Extension::Log);
+        assert_eq!(
+            BotModule("test".to_string()),
+            BotModule("Test".to_lowercase())
+        );
+    }
+
+
+
 
     /*
         Possible Tests

From 072903882de4e57ec297ce41606b2a98b168b153 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 08:40:09 -0400
Subject: [PATCH 16/98] botmodule case insensitive

---
 src/core/botmodules.rs | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 568683a..cc4b1aa 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -272,11 +272,22 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 
-#[derive(Debug, PartialEq, Eq, Hash, Clone)]
+// #[derive(Debug, PartialEq, Eq, Hash, Clone)]
+#[derive(Debug, Hash, Clone)]
 pub enum ModType {
     BotModule(String),
 }
 
+impl PartialEq for ModType {
+    fn eq(&self, other: &Self) -> bool {
+        let BotModule(name1) = self.clone();
+        let BotModule(name2) = other.clone();
+        name1.to_lowercase() == name2.to_lowercase()
+    }
+}
+impl Eq for ModType {}
+
+
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum ModGroup {
     Core,
@@ -1287,10 +1298,10 @@ mod core_modulesmanager {
     use super::*;
 
     #[test]
-    fn WIP_case_insensitive_test() {
+    fn case_insensitive_test() {
         Log::set_file_ext(Extension::Log);
         assert_eq!(
-            BotModule("test".to_string()),
+            BotModule("Test".to_string()),
             BotModule("Test".to_lowercase())
         );
     }

From 8b4c21ba58604332c307cd94e0d4bc8cd4d32e83 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 17:06:09 -0400
Subject: [PATCH 17/98] unit tests

---
 src/core/botmodules.rs | 904 ++++++++++++++++++++++++++++++++++++++++-
 src/core/identity.rs   |   6 +-
 2 files changed, 886 insertions(+), 24 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index cc4b1aa..a3866dd 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -28,7 +28,7 @@ use std::sync::Arc;
 // use futures::stream::iter;
 use twitch_irc::message::PrivmsgMessage;
 
-// use casual_logger::Log;
+use casual_logger::Log;
 
 use tokio::sync::RwLock;
 
@@ -38,7 +38,7 @@ use self::bot_actions::actions_util::BotAR;
 use crate::core::bot_actions::actions_util;
 use crate::core::botinstance::{BotInstance, ChType,ChangeResult};
 use crate::core::botlog;
-use crate::core::identity::{self, Permissible};
+use crate::core::identity::{self, Permissible,IdentityManager};
 
 use crate::core::bot_actions;
 pub use ChType::Channel;
@@ -598,7 +598,8 @@ impl ModulesManager {
         trg_module: ModType,
         // channel: Option<ChType>,
         trg_level: StatusLvl,
-        bot: BotAR,
+        // bot: BotAR,
+        id: Arc<RwLock<IdentityManager>>,
     ) -> ChangeResult 
     {
 
@@ -631,8 +632,20 @@ impl ModulesManager {
           */
 
 
-        let botlock = bot.read().await;
-        let id = botlock.get_identity();
+        // [x] Validate in trg_module first
+
+        // let botlock = bot.read().await;
+        // let modmgr = Arc::clone(&botlock.botmodules);
+        let modlist = self.moduleslist().await;
+        let rslt =  modlist.get(&trg_module);
+
+        if let None = rslt {
+            return ChangeResult::Failed("Module doesn't exist".to_string());
+        }
+
+
+        // let botlock = bot.read().await;
+        // let id = botlock.get_identity();
         let mut idlock = id.write().await;
 
         // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
@@ -657,17 +670,37 @@ impl ModulesManager {
             identity::UserRole::Broadcaster,
         ]).await;
 
+
+        // botlog::debug(
+        //     &format!("FAILURE BEFORE Let statements involves : 
+        //         admin_level_access : {:?} ; chnl_elevated_access : {:?}", 
+        //         admin_level_access , chnl_elevated_access),
+        //     Some("botmodules.rs > exec_enable()".to_string()),
+        //     None,
+        // );
+
+
+
         if let Permissible::Allow = admin_level_access {
             if let Permissible::Block = chnl_elevated_access {
+                
+        botlog::debug(
+            &format!("?? REACHED INNER TIER : 
+                admin_level_access : {:?} ; chnl_elevated_access : {:?}", 
+                admin_level_access , chnl_elevated_access),
+            Some("botmodules.rs > exec_enable()".to_string()),
+            None,
+        );
                 match trg_level {
                     StatusLvl::Instance => {
                         self.set_instance_enabled(trg_module.clone()).await;
-                        ChangeResult::Success("Enabled at Instance Level".to_string())
+                        return ChangeResult::Success("Enabled at Instance Level".to_string());
                     },
                     StatusLvl::Ch(_) => {
-                        ChangeResult::Failed("Promote yourself Temporarily First".to_string())
+                        return ChangeResult::Failed("Promote yourself Temporarily First".to_string());
                     },
                 };
+                
             }
         }
 
@@ -684,11 +717,11 @@ impl ModulesManager {
             if let Permissible::Allow = chnl_elevated_access {
                 match trg_level.clone() {
                     StatusLvl::Instance => {
-                        ChangeResult::Failed("You're not allowed".to_string())
+                        return ChangeResult::Failed("You're not allowed".to_string());
                     },
                     StatusLvl::Ch(in_chnl) => {
                         self.set_ch_enabled(trg_module.clone(), in_chnl).await;
-                        ChangeResult::Success("Enabled at Channel Level".to_string())
+                        return ChangeResult::Success("Enabled at Channel Level".to_string());
                     },
                 };
             }
@@ -709,17 +742,39 @@ impl ModulesManager {
                 match trg_level {
                     StatusLvl::Instance => {
                         self.set_instance_enabled(trg_module.clone()).await;
-                        ChangeResult::Success("Enabled at Instance Level".to_string())
+                        return ChangeResult::Success("Enabled at Instance Level".to_string());
                     },
                     StatusLvl::Ch(in_chnl) => {
                         self.set_ch_enabled(trg_module.clone(), in_chnl).await;
-                        ChangeResult::Success("Enabled at Channel Level".to_string())
+                        return ChangeResult::Success("Enabled at Channel Level".to_string());
                     },
                 };
             }
         }
 
 
+        // Respond in case of General Chatter
+        // The below should NOT be required , as current internal logic would prevent
+        //   a BotCommand to be ran by a Chatter if it requires any special roles and
+        //   that chatter does not have htose roles
+        // However, below is added to satisfy unit tests
+
+
+        if let Permissible::Block = admin_level_access {
+            if let Permissible::Block = chnl_elevated_access {
+                match trg_level {
+                    StatusLvl::Instance => {
+                        return ChangeResult::Failed("You're not allowed".to_string());
+                    },
+                    StatusLvl::Ch(_) => {
+                        return ChangeResult::Failed("You're not allowed".to_string());
+                    },
+                };
+            }
+        }
+
+
+
 
 
         // =======================
@@ -779,8 +834,17 @@ impl ModulesManager {
 
         // } 
 
+        botlog::debug(
+            &format!("FAILURE involves : 
+                admin_level_access : {:?} ; chnl_elevated_access : {:?}", 
+                admin_level_access , chnl_elevated_access),
+            Some("botmodules.rs > exec_enable()".to_string()),
+            None,
+        );
 
 
+        Log::flush();
+
         ChangeResult::Failed("ERROR : Not implemented yet".to_string())
     }
 
@@ -793,7 +857,8 @@ impl ModulesManager {
         // channel: Option<ChType>,
         trg_level: StatusLvl,
         force: bool,
-        bot: BotAR,
+        // bot: BotAR,
+        id: Arc<RwLock<IdentityManager>>,
     ) -> ChangeResult 
     {
 
@@ -818,10 +883,21 @@ impl ModulesManager {
                 3c. , and is -f (forced) , return a Success    
          */
 
+        // [x] Validate in trg_module first
+
+        // let botlock = bot.read().await;
+        // let modmgr = Arc::clone(&botlock.botmodules);
+        let modlist = self.moduleslist().await;
+        let rslt =  modlist.get(&trg_module);
+
+        if let None = rslt {
+            return ChangeResult::Failed("Module doesn't exist".to_string());
+        }
+
          
 
-        let botlock = bot.read().await;
-        let id = botlock.get_identity();
+        // let botlock = bot.read().await;
+        // let id = botlock.get_identity();
         let mut idlock = id.write().await;
 
         // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
@@ -866,10 +942,10 @@ impl ModulesManager {
                     match trg_level {
                         StatusLvl::Instance => {
                             self.set_instance_disabled(trg_module.clone()).await;
-                            ChangeResult::Success("Disabled at Instance Level".to_string())
+                            return ChangeResult::Success("Disabled at Instance Level".to_string());
                         },
                         StatusLvl::Ch(_) => {
-                            ChangeResult::Failed("Promote yourself Temporarily First".to_string())
+                            return ChangeResult::Failed("Promote yourself Temporarily First".to_string());
                         },
                     };
                 }
@@ -893,11 +969,11 @@ impl ModulesManager {
                 } else {
                     match trg_level.clone() {
                         StatusLvl::Instance => {
-                            ChangeResult::Failed("You're not allowed".to_string())
+                            return ChangeResult::Failed("You're not allowed".to_string());
                         },
                         StatusLvl::Ch(in_chnl) => {
                             self.set_ch_disabled(trg_module.clone(), in_chnl).await;
-                            ChangeResult::Success("Disabled at Channel Level".to_string())
+                            return ChangeResult::Success("Disabled at Channel Level".to_string());
                         },
                     };
                 }
@@ -923,11 +999,11 @@ impl ModulesManager {
                     match trg_level {
                         StatusLvl::Instance => {
                             self.set_instance_disabled(trg_module.clone()).await;
-                            ChangeResult::Success("Disabled at Instance Level".to_string())
+                            return ChangeResult::Success("Disabled at Instance Level".to_string());
                         },
                         StatusLvl::Ch(in_chnl) => {
                             self.set_ch_disabled(trg_module.clone(), in_chnl).await;
-                            ChangeResult::Success("Disabled at Channel Level".to_string())
+                            return ChangeResult::Success("Disabled at Channel Level".to_string());
                         },
                     };
                 }
@@ -935,6 +1011,29 @@ impl ModulesManager {
         }
 
 
+        
+        // Respond in case of General Chatter
+        // The below should NOT be required , as current internal logic would prevent
+        //   a BotCommand to be ran by a Chatter if it requires any special roles and
+        //   that chatter does not have htose roles
+        // However, below is added to satisfy unit tests
+
+
+        if let Permissible::Block = admin_level_access {
+            if let Permissible::Block = chnl_elevated_access {
+                match trg_level {
+                    StatusLvl::Instance => {
+                        return ChangeResult::Failed("You're not allowed".to_string());
+                    },
+                    StatusLvl::Ch(_) => {
+                        return ChangeResult::Failed("You're not allowed".to_string());
+                    },
+                };
+            }
+        }
+
+
+
          ChangeResult::Failed("ERROR : Not implemented yet".to_string())
     }
 
@@ -1301,8 +1400,8 @@ mod core_modulesmanager {
     fn case_insensitive_test() {
         Log::set_file_ext(Extension::Log);
         assert_eq!(
-            BotModule("Test".to_string()),
-            BotModule("Test".to_lowercase())
+            BotModule("TEST".to_string()),
+            BotModule("test".to_string())
         );
     }
 
@@ -1545,4 +1644,765 @@ mod core_modulesmanager {
     }
 
 
+    
+
+    /*
+        1. Create new ModulesManager & Identity Manager
+        2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        3. affirm when BotAdmin attempts to exec_enable on the following
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+        4. affirm when BotAdmin attempts to exec_disable on the following 
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+            d. force disable
+
+
+        1. Create new ModulesManager & Identity Manager
+        2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        3. affirm when Mod attempts to exec_enable on the following
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+        4. affirm when Mod attempts to exec_disable on the following 
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+            d. force disable
+    
+     */
+
+     async fn inner_enable_disable_complex(
+        requestor:String,
+        channel:ChType,
+        idmgr:IdentityManager,
+        modsmgr:Arc<ModulesManager>) 
+    {
+
+        /*
+            Parent Tests would involve : 
+                - Testing with a BotAdmin User
+                - Testing with a Mod User
+                - Testing with a Regular Chatter
+         */
+
+        enum TestScenarios {
+            BotadminUser,
+            ModUser,
+            RegularChatter,
+            // ModuleDoesNotExist, // preferring instead to handle in it's own smaller test
+        }
+
+        
+        // let channel = ChType::Channel("somechannel".to_string());
+
+
+        // let mut idlock = idmgr.write().await;
+        let mut idlock = idmgr.clone();
+
+        // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
+
+        // let arb_chnl = match trg_level.clone() {
+        //     StatusLvl::Instance => ChType::Channel(requestor.to_lowercase()),
+        //     StatusLvl::Ch(a) => a,
+        // };
+
+        let requestor_badge = None; // If they are a Mod on the Given Channel already, that can be evaluated without the current badge
+
+        const OF_CMD_CHANNEL:ChType = Channel(String::new());
+        
+        let (admin_level_access,_) = idlock.can_user_run(requestor.clone(), channel.clone(), requestor_badge.clone(), 
+        vec![
+            identity::UserRole::BotAdmin,
+        ]).await;
+
+
+        let (chnl_elevated_access,_) = idlock.can_user_run(requestor.clone(), channel.clone(), requestor_badge.clone(), 
+        vec![
+            identity::UserRole::Mod(OF_CMD_CHANNEL),
+            identity::UserRole::SupMod(OF_CMD_CHANNEL),
+            identity::UserRole::Broadcaster,
+        ]).await;
+
+
+        let current_test_scenario = 
+            match admin_level_access {
+                Permissible::Allow => {
+                    match chnl_elevated_access {
+                        Permissible::Allow => { TestScenarios::BotadminUser },
+                        Permissible::Block => { TestScenarios::BotadminUser }
+                    }
+                },
+                Permissible::Block => {
+                    match chnl_elevated_access {
+                        Permissible::Allow => { TestScenarios::ModUser },
+                        Permissible::Block => { TestScenarios::RegularChatter }
+                    }
+                }
+            };
+
+
+
+        // [x] 2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        let in_module = BotModule("Experiments01".to_string());
+        let in_modgroup = ModGroup::Custom;
+
+        // match current_test_scenario {
+        //     TestScenarios::BotadminUser => modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await,
+        //     _ => self::panic!("Scenario not handled"),
+        // }
+
+        modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
+
+        let in_module = match current_test_scenario {
+            // TestScenarios::ModuleDoesNotExist => BotModule("NonExisting_Module".to_string()),
+            _ => in_module,
+        };
+
+
+        /*
+            [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+                    a. Channel Level , where they are not a Mod
+        */
+
+
+        // [-] requestor_badge: Option<ChatBadge>,
+
+        // [x] trg_module: ModType,
+        let trg_module = in_module;
+
+        // [x] trg_level: StatusLvl,
+
+        let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+
+
+        // [x] id: Arc<RwLock<IdentityManager>>,
+        let id = Arc::new(RwLock::new(idmgr.clone()));
+
+
+        let rslt = modsmgr.exec_enable(requestor.clone(), 
+            None, 
+            trg_module.clone(), 
+            trg_level.clone(), 
+            id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Failed("Promote yourself Temporarily First".to_string()));
+
+        match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                assert_eq!(rslt,ChangeResult::Failed("Promote yourself Temporarily First".to_string())),
+            TestScenarios::ModUser => 
+                assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string())),
+            TestScenarios::RegularChatter => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // TestScenarios::ModuleDoesNotExist => 
+            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        }
+
+
+        /*
+            [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+                    b. Channel Level , when they are a Mod
+         */
+
+        // [x] requestor_badge: Option<ChatBadge>,
+        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+        let requestor_badge =   match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                Some(ChatBadge::Mod), // setting badge to Mod -- for the Problem Scenario . They are both BotAdmin & Mod
+            TestScenarios::ModUser => 
+                Some(ChatBadge::Mod), // setting badge to Mod
+            TestScenarios::RegularChatter => 
+                None, // setting badge to None
+            // TestScenarios::ModuleDoesNotExist => 
+            //     None,
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        } ;
+        
+
+        let rslt = modsmgr.exec_enable(requestor.clone(), 
+            requestor_badge, 
+            trg_module.clone(), 
+            trg_level.clone(), 
+            id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string()));
+
+        match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string())),
+            TestScenarios::ModUser => 
+                assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string())),
+            TestScenarios::RegularChatter => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // TestScenarios::ModuleDoesNotExist => 
+            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),    
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        }
+
+        /*
+            [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+                    c. Instance Level
+         */
+
+         let trg_level = StatusLvl::Instance; // setting to Instance level
+
+         let requestor_badge = match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                None,
+            TestScenarios::ModUser => 
+                Some(ChatBadge::Mod),
+            TestScenarios::RegularChatter => 
+                None, // setting badge to None
+            // TestScenarios::ModuleDoesNotExist => 
+            //     None, // setting badge to None
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        };
+
+         let rslt = modsmgr.exec_enable(requestor.clone(), 
+             requestor_badge, // passing based on scenario 
+             trg_module.clone(), 
+             trg_level.clone(), 
+             id.clone()).await;
+ 
+        //  assert_eq!(rslt,ChangeResult::Success("Enabled at Instance Level".to_string()));
+
+         match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                assert_eq!(rslt,ChangeResult::Success("Enabled at Instance Level".to_string())),
+            TestScenarios::ModUser => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            TestScenarios::RegularChatter => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // TestScenarios::ModuleDoesNotExist => 
+            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        }
+
+         /*
+            [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
+                a. Channel Level , where they are not a Mod
+          */
+
+        let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+
+        let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+            None, // Does not have a ChatBadge like Mod
+            trg_module.clone(), 
+            trg_level.clone(),
+            false, 
+            id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
+        match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
+            TestScenarios::ModUser => 
+                assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
+            TestScenarios::RegularChatter => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // TestScenarios::ModuleDoesNotExist => 
+            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        }
+
+
+          /*
+            [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
+                b. Channel Level , when they are a Mod
+          */
+
+          
+        let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+        let requestor_badge = match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                None,
+            TestScenarios::ModUser => 
+                Some(ChatBadge::Mod),
+            TestScenarios::RegularChatter => 
+                None, // setting badge to None
+            // TestScenarios::ModuleDoesNotExist => 
+            //     None,
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        };
+
+        let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+            requestor_badge, 
+            trg_module.clone(), 
+            trg_level.clone(),
+            false, 
+            id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
+        match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
+            TestScenarios::ModUser => 
+                assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
+            TestScenarios::RegularChatter => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // TestScenarios::ModuleDoesNotExist => 
+            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        }
+
+
+          /*
+            [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
+                c. Instance Level
+          */
+
+          let trg_level = StatusLvl::Instance; // setting to Instance level
+        //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+  
+          let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+              None, // Does not have a ChatBadge like Mod
+              trg_module.clone(), 
+              trg_level.clone(),
+              false, 
+              id.clone()).await;
+  
+        //   assert_eq!(rslt,ChangeResult::Success("Disabled at Instance Level".to_string()));
+          match current_test_scenario {
+            TestScenarios::BotadminUser => 
+                assert_eq!(rslt,ChangeResult::Success("Disabled at Instance Level".to_string())),
+            TestScenarios::ModUser => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            TestScenarios::RegularChatter => 
+                assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // TestScenarios::ModuleDoesNotExist =>
+            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+            // _ => 
+            //     self::panic!("Scenario not handled"),
+        }
+
+          /*
+                [ ] 4. affirm when BotAdmin attempts to exec_disable on the following 
+                    d. force disable
+          */
+
+          let trg_level = StatusLvl::Instance; // setting to Instance level
+          //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+    
+            let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+                None, // Does not have a ChatBadge like Mod
+                trg_module.clone(), 
+                trg_level.clone(),
+                true, // force flag - true  
+                id.clone()).await;
+    
+            // assert_eq!(rslt,ChangeResult::Success("Forced Disable".to_string()));
+            match current_test_scenario {
+                TestScenarios::BotadminUser => 
+                    assert_eq!(rslt,ChangeResult::Success("Forced Disable".to_string())),
+                TestScenarios::ModUser => 
+                    assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+                TestScenarios::RegularChatter => 
+                    assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+                // TestScenarios::ModuleDoesNotExist => 
+                //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
+                // _ => 
+                //     self::panic!("Scenario not handled"),
+            }
+
+
+    }
+
+
+     #[tokio::test]
+     async fn enable_disable_bot_admin_workflow() {
+        Log::set_file_ext(Extension::Log);
+        /*
+
+        1. Create new ModulesManager & Identity Manager
+        2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        3. affirm when BotAdmin attempts to exec_enable on the following
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+        4. affirm when BotAdmin attempts to exec_disable on the following 
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+            d. force disable
+
+         */
+
+
+        // [x] 1. Create new ModulesManager & Identity Manager
+        let idmgr = IdentityManager::init();
+        let modsmgr = ModulesManager::init().await;
+
+        // // [x] 2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        // let in_module = BotModule("Experiments01".to_string());
+        // let in_modgroup = ModGroup::Custom;
+
+        // modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
+
+
+        /*
+            [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+                    a. Channel Level , where they are not a Mod
+         */
+
+        // [x] Create BotAdmin first
+
+        let requestor = "botadministrator".to_string();
+        // let botadmin_badge = &None;
+
+        idmgr.affirm_chatter_in_db(requestor.clone()).await;
+        idmgr
+            .add_role(requestor.clone(), identity::UserRole::BotAdmin)
+            .await;
+
+        let rslt = idmgr
+            .getspecialuserroles(requestor.clone(), None)
+            .await;
+
+        assert!(rslt.contains(&identity::UserRole::BotAdmin));
+
+        let channel = ChType::Channel("somechannel".to_string());
+
+
+        inner_enable_disable_complex(requestor, channel, idmgr, modsmgr).await;
+
+
+        /*
+            pub async fn exec_enable(
+                &self,
+                requestor: String,
+                requestor_badge: Option<ChatBadge>,
+                trg_module: ModType,
+                trg_level: StatusLvl,
+                id: Arc<RwLock<IdentityManager>>,
+            ) -> ChangeResult 
+
+         */
+
+        /*
+            [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+                    a. Channel Level , where they are not a Mod
+        */
+
+
+        // [-] requestor_badge: Option<ChatBadge>,
+
+        // [x] trg_module: ModType,
+        // let trg_module = in_module;
+
+        // [x] trg_level: StatusLvl,
+
+        // let channel = ChType::Channel("somechannel".to_string());
+        // let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+
+
+        // // [x] id: Arc<RwLock<IdentityManager>>,
+        // let id = Arc::new(RwLock::new(idmgr));
+
+
+        // let rslt = modsmgr.exec_enable(requestor.clone(), 
+        //     None, 
+        //     trg_module.clone(), 
+        //     trg_level.clone(), 
+        //     id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Failed("Promote yourself Temporarily First".to_string()));
+
+        // /*
+        //     [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+        //             b. Channel Level , when they are a Mod
+        //  */
+
+        // // [x] requestor_badge: Option<ChatBadge>,
+        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+
+        // let rslt = modsmgr.exec_enable(requestor.clone(), 
+        //     Some(requestor_badge), 
+        //     trg_module.clone(), 
+        //     trg_level.clone(), 
+        //     id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string()));
+
+        // /*
+        //     [x] 3. affirm when BotAdmin attempts to exec_enable on the following
+        //             c. Instance Level
+        //  */
+
+        //  let trg_level = StatusLvl::Instance; // setting to Instance level
+
+        //  let rslt = modsmgr.exec_enable(requestor.clone(), 
+        //      None, // setting them back to Non-Mod
+        //      trg_module.clone(), 
+        //      trg_level.clone(), 
+        //      id.clone()).await;
+ 
+        //  assert_eq!(rslt,ChangeResult::Success("Enabled at Instance Level".to_string()));
+
+        //  /*
+        //     [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
+        //         a. Channel Level , where they are not a Mod
+        //   */
+
+        // let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+
+        // let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+        //     None, // Does not have a ChatBadge like Mod
+        //     trg_module.clone(), 
+        //     trg_level.clone(),
+        //     false, 
+        //     id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
+
+
+        //   /*
+        //     [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
+        //         b. Channel Level , when they are a Mod
+        //   */
+
+          
+        // let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+
+        // let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+        //     Some(requestor_badge), 
+        //     trg_module.clone(), 
+        //     trg_level.clone(),
+        //     false, 
+        //     id.clone()).await;
+
+        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
+
+        //   /*
+        //     [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
+        //         c. Instance Level
+        //   */
+
+        //   let trg_level = StatusLvl::Instance; // setting to Instance level
+        // //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+  
+        //   let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+        //       None, // Does not have a ChatBadge like Mod
+        //       trg_module.clone(), 
+        //       trg_level.clone(),
+        //       false, 
+        //       id.clone()).await;
+  
+        //   assert_eq!(rslt,ChangeResult::Success("Disabled at Instance Level".to_string()));
+
+        //   /*
+        //         [ ] 4. affirm when BotAdmin attempts to exec_disable on the following 
+        //             d. force disable
+        //   */
+
+        //   let trg_level = StatusLvl::Instance; // setting to Instance level
+        //   //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+    
+        //     let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
+        //         None, // Does not have a ChatBadge like Mod
+        //         trg_module.clone(), 
+        //         trg_level.clone(),
+        //         true, // force flag - true  
+        //         id.clone()).await;
+    
+        //     assert_eq!(rslt,ChangeResult::Success("Forced Disable".to_string()));
+  
+
+
+
+     }
+
+
+     
+     #[tokio::test]
+     async fn enable_disable_mod_workflow() {
+        Log::set_file_ext(Extension::Log);
+
+        /*
+        1. Create new ModulesManager & Identity Manager
+        2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        3. affirm when Mod attempts to exec_enable on the following
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+        4. affirm when Mod attempts to exec_disable on the following 
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+            d. force disable
+         */
+
+        
+        // [x] 1. Create new ModulesManager & Identity Manager
+        let idmgr = IdentityManager::init();
+        let modsmgr = ModulesManager::init().await;
+
+
+         let requestor = "mod_user".to_string();
+         // let botadmin_badge = &None;
+         let channel = ChType::Channel("somechannel".to_string());
+ 
+ 
+         idmgr.affirm_chatter_in_db(requestor.clone()).await;
+         idmgr
+             .add_role(requestor.clone(), identity::UserRole::Mod(channel.clone()))
+             .await;
+ 
+         let rslt = idmgr
+             .getspecialuserroles(
+                requestor.clone(), 
+                Some(channel.clone()) // None if BotAdmin ; Otherwise, pass Some(Channel)
+            )
+             .await;
+ 
+         assert!(rslt.contains(&identity::UserRole::Mod(channel.clone())));
+ 
+ 
+         inner_enable_disable_complex(requestor, channel, idmgr, modsmgr).await;
+ 
+ 
+        
+     }
+
+     #[tokio::test]
+     async fn enable_disable_chatter_workflow() {
+        Log::set_file_ext(Extension::Log);
+
+        
+        /*
+        1. Create new ModulesManager & Identity Manager
+        2. modmgr.affirm_in_statusdb(Experiments01,Custom)
+
+        3. affirm when Mod attempts to exec_enable on the following
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+        4. affirm when Mod attempts to exec_disable on the following 
+            a. Channel Level , where they are not a Mod
+            b. Channel Level , when they are a Mod
+            c. Instance Level
+            d. force disable
+         */
+
+        
+        // [x] 1. Create new ModulesManager & Identity Manager
+        let idmgr = IdentityManager::init();
+        let modsmgr = ModulesManager::init().await;
+
+
+         let requestor = "regular_user".to_string();
+         // let botadmin_badge = &None;
+         let channel = ChType::Channel("somechannel".to_string());
+ 
+ 
+         idmgr.affirm_chatter_in_db(requestor.clone()).await;
+        //  idmgr
+        //      .add_role(requestor.clone(), identity::UserRole::Mod(channel.clone()))
+        //      .await;
+ 
+         let rslt = idmgr
+             .getspecialuserroles(
+                requestor.clone(), 
+                Some(channel.clone()) // None if BotAdmin ; Otherwise, pass Some(Channel)
+            )
+             .await;
+ 
+         assert!(!rslt.contains(&identity::UserRole::Mod(channel.clone())) || 
+                !rslt.contains(&identity::UserRole::BotAdmin));
+ 
+ 
+         inner_enable_disable_complex(requestor, channel, idmgr, modsmgr).await;
+
+     }
+
+
+     #[tokio::test]
+     async fn enable_disable_modulenotexist_workflow() {
+        Log::set_file_ext(Extension::Log);
+
+        
+        // [x] 1. Create new ModulesManager & Identity Manager
+        let idmgr = IdentityManager::init();
+        let modsmgr = ModulesManager::init().await;
+
+
+         let requestor = "regular_user".to_string();
+         // let botadmin_badge = &None;
+         let channel = ChType::Channel("somechannel".to_string());
+ 
+ 
+         idmgr.affirm_chatter_in_db(requestor.clone()).await;
+        //  idmgr
+        //      .add_role(requestor.clone(), identity::UserRole::Mod(channel.clone()))
+        //      .await;
+ 
+         let rslt = idmgr
+             .getspecialuserroles(
+                requestor.clone(), 
+                Some(channel.clone()) // None if BotAdmin ; Otherwise, pass Some(Channel)
+            )
+             .await;
+ 
+         assert!(!rslt.contains(&identity::UserRole::Mod(channel.clone())) || 
+                !rslt.contains(&identity::UserRole::BotAdmin));
+
+        // After above, regular chatter is created
+
+        // [x] 2. modmgr.affirm_in_statusdb(Existing_Module,Custom)
+
+        let in_module = BotModule("Existing_Module".to_string());
+        let in_modgroup = ModGroup::Custom;
+
+        modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
+
+
+        let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
+
+
+        // [x] Test with Non Existing module > exec
+
+        let trg_module = BotModule("Non_Existent_Module".to_string());
+
+        let rslt = modsmgr.exec_enable(requestor.clone(), 
+            None, 
+            trg_module.clone(), 
+            trg_level.clone(), 
+            Arc::new(RwLock::new(idmgr.clone()))).await;
+
+        assert_eq!(rslt,ChangeResult::Failed("Module doesn't exist".to_string()));
+
+        // [ ] Test with Non Existing module > disable
+
+        let trg_module = BotModule("Non_Existent_Module".to_string());
+
+        let rslt = modsmgr.exec_disable(requestor.clone(), 
+            None, 
+            trg_module.clone(), 
+            trg_level.clone(), 
+            false,
+            Arc::new(RwLock::new(idmgr))).await;
+
+        assert_eq!(rslt,ChangeResult::Failed("Module doesn't exist".to_string()));
+
+     }
+
 }
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 84905cc..accda4f 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -630,7 +630,8 @@ impl IdentityManager {
         }
     }
 
-    async fn add_role(&self, trgchatter: String, trg_role: UserRole) {
+    // => 03.22 - Force - Made public because botmodules unit tests
+    pub async fn add_role(&self, trgchatter: String, trg_role: UserRole) {
         let mut srulock = self.special_roles_users.write().await;
         let mut usrrolelock = srulock
             .get_mut(&trgchatter)
@@ -652,7 +653,8 @@ impl IdentityManager {
         }
     }
 
-    async fn affirm_chatter_in_db(&self, trgchatter: String) {
+    // => 03.22 - Force - Made public because botmodules unit tests
+    pub async fn affirm_chatter_in_db(&self, trgchatter: String) {
         let mut srulock = self.special_roles_users.write().await;
         srulock
             .entry(trgchatter.clone())

From 7757dd18200bfceb69980b4a5a8511a8b34e090b Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 18:02:31 -0400
Subject: [PATCH 18/98] (cont) enable cmd logic

---
 src/core/botinstance.rs |  2 +-
 src/core/botmodules.rs  | 76 ++++++++++++++++++++++++++---------------
 2 files changed, 49 insertions(+), 29 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 2e30421..733b89a 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -25,7 +25,7 @@ use crate::core::botlog;
 use crate::core::chat::Chat;
 
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Clone)]
 pub enum ChangeResult {
     Success(String),
     Failed(String),
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index a3866dd..a199481 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -108,7 +108,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 
-        // [ ] Unwraps arguments from message
+        // [x] Unwraps arguments from message
 
         let (arg1, arg2) = {
 
@@ -137,11 +137,11 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         */
 
 
-        // [ ] requestor: String,
-        let requester = msg.clone().sender.name;
+        // [x] requestor: String,
+        let requestor = msg.clone().sender.name;
 
 
-        // [ ] requestor_badge: Option<ChatBadge>,
+        // [x] requestor_badge: Option<ChatBadge>,
 
         let mut requestor_badge_mut: Option<ChatBadge> = None;
 
@@ -156,41 +156,36 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let requestor_badge = requestor_badge_mut;
 
 
-        // [ ] trg_module: ModType,
-        //      - [ ] Need to validate an actual ModType - otherwise, fail or exit the cmd
+        // [x] trg_module: ModType,
+        //      - [x] Need to validate an actual ModType - otherwise, fail or exit the cmd
     
         let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
 
-        if let Some(trg_module_str) = trg_module {
+        // if no trg_module was passed 
+        if let None = trg_module {
 
             let botlock = bot.read().await;
-            let modmgr = Arc::clone(&botlock.botmodules);
-            let modlist = modmgr.moduleslist().await;
-            let rslt =  modlist.get(&ModType::BotModule(trg_module_str.to_string()));
+            
+            let outmsg = "uuh You need to pass a module";
 
-            if let None = rslt {
+            botlog::debug(
+                outmsg,
+                Some("botmodules.rs > cmd_enable()".to_string()),
+                Some(&msg),
+            );
+    
+            botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(&msg, outmsg.to_string())
+                .await;
 
-                let outmsg = "uuh module doesn't exist";
-
-                botlog::debug(
-                    outmsg,
-                    Some("botmodules.rs > cmd_enable()".to_string()),
-                    Some(&msg),
-                );
-        
-                botlock
-                    .botmgrs
-                    .chat
-                    .say_in_reply_to(&msg, outmsg.to_string())
-                    .await;
-
-                return;
-            }
+            return;
 
         }
         
 
-        // [ ] trg_level: StatusLvl,
+        // [x] trg_level: StatusLvl,
 
         let currchnl = msg.channel_login.to_lowercase();
 
@@ -200,8 +195,33 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             else { StatusLvl::Ch(ChType::Channel(currchnl)) }
             ; 
 
+        
+    
+        let botlock = bot.read().await;
+        let modmgr = Arc::clone(&botlock.botmodules);
+        let id = botlock.get_identity();
 
 
+        // modmgr.exec_enable(requestor, requestor_badge, trg_module, trg_level, id)
+        let rslt = modmgr.exec_enable(
+            requestor, 
+            requestor_badge, 
+            ModType::BotModule(trg_module.unwrap().to_string()), 
+            trg_level, 
+            id).await;
+
+
+        let outmsg = match rslt.clone() {
+            ChangeResult::Failed(a) => format!("Stare Failed : {}",a),
+            ChangeResult::NoChange(a) => format!("Hmm No Change : {}",a),
+            ChangeResult::Success(a) => format!("YAAY Success : {}",a),
+        };
+
+        botlock
+            .botmgrs
+            .chat
+            .say_in_reply_to(&msg, outmsg.to_string())
+            .await;
 
     }
 

From 29c8f745319ffae0a8959861aaeda82aa5dcd7b4 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 18:16:41 -0400
Subject: [PATCH 19/98] (cont) disable cmd logic

---
 src/core/botmodules.rs | 123 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index a199481..df0595f 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -223,6 +223,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             .say_in_reply_to(&msg, outmsg.to_string())
             .await;
 
+
     }
 
 
@@ -281,6 +282,128 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 3c. , and is -f (forced) , return a Success    
          */
 
+
+                 // [x] Unwraps arguments from message
+
+        let (arg1, arg2) = {
+
+            let mut argv = msg.message_text.split(' ');
+
+            argv.next(); // Skip the command name
+
+            let arg1 = argv.next();
+
+            let arg2 = argv.next();
+
+            (arg1, arg2)
+        };
+
+
+        /* -- Related function to call later
+            exec_disable(
+                &self,
+                requestor: String,
+                requestor_badge: Option<ChatBadge>,
+                trg_module: ModType,
+                // channel: Option<ChType>,
+                trg_level: StatusLvl,
+                force: bool,
+                // bot: BotAR,
+                id: Arc<RwLock<IdentityManager>>,
+            ) -> ChangeResult 
+        */
+
+
+        // [x] requestor: String,
+        let requestor = msg.clone().sender.name;
+
+
+        // [x] requestor_badge: Option<ChatBadge>,
+
+        let mut requestor_badge_mut: Option<ChatBadge> = None;
+
+        for b in &msg.badges {
+            if b.name == "moderator" {
+                requestor_badge_mut = Some(ChatBadge::Mod);
+            } else if b.name == "broadcaster" {
+                requestor_badge_mut = Some(ChatBadge::Broadcaster);
+            }
+        }
+
+        let requestor_badge = requestor_badge_mut;
+
+                // [x] trg_module: ModType,
+        //      - [x] Need to validate an actual ModType - otherwise, fail or exit the cmd
+    
+        let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
+
+        // if no trg_module was passed 
+        if let None = trg_module {
+
+            let botlock = bot.read().await;
+            
+            let outmsg = "uuh You need to pass a module";
+
+            botlog::debug(
+                outmsg,
+                Some("botmodules.rs > cmd_disable()".to_string()),
+                Some(&msg),
+            );
+    
+            botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(&msg, outmsg.to_string())
+                .await;
+
+            return;
+
+        }
+        
+
+        
+        // [x] trg_level: StatusLvl,
+
+        let currchnl = msg.channel_login.to_lowercase();
+
+        let trg_level = 
+            if arg1 == Some("-i") { StatusLvl::Instance } 
+            else if arg1 == Some("-f") { StatusLvl::Instance }
+            else { StatusLvl::Ch(ChType::Channel(currchnl)) }
+            ; 
+
+
+
+        let botlock = bot.read().await;
+        let modmgr = Arc::clone(&botlock.botmodules);
+        let id = botlock.get_identity();
+
+        let force = arg1 == Some("-f"); 
+
+        // modmgr.exec_enable(requestor, requestor_badge, trg_module, trg_level, id)
+        let rslt = modmgr.exec_disable(
+            requestor, 
+            requestor_badge, 
+            ModType::BotModule(trg_module.unwrap().to_string()), 
+            trg_level, 
+            force, 
+            id).await;
+            
+
+        let outmsg = match rslt.clone() {
+            ChangeResult::Failed(a) => format!("Stare Failed : {}",a),
+            ChangeResult::NoChange(a) => format!("Hmm No Change : {}",a),
+            ChangeResult::Success(a) => format!("YAAY Success : {}",a),
+        };
+
+        botlock
+            .botmgrs
+            .chat
+            .say_in_reply_to(&msg, outmsg.to_string())
+            .await;
+    
+
+
     }
 
 

From ba6117d6925fd5ebc5d4a0f3724b8e5fdd486860 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 18:32:03 -0400
Subject: [PATCH 20/98] validate status

---
 src/core/botinstance.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 733b89a..5e70806 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -41,6 +41,8 @@ pub enum ChType {
 
 pub use ChType::Channel;
 
+use super::botmodules::StatusType;
+
 #[derive(Clone)]
 pub struct BotManagers {
     pub identity: Arc<RwLock<IdentityManager>>,
@@ -293,6 +295,23 @@ impl BotInstance {
                             let botlock = bot.read().await;
                             let id = botlock.get_identity();
 
+                            // [ ] Check first if the Module for that Given Command is Enabled or Disabled on the given Channel
+                            let modmgr = Arc::clone(&botlock.botmodules);
+                            let modstatus = modmgr.modstatus(
+                                c.module.clone(), 
+                                ChType::Channel(msg.channel_login.to_string())).await;
+
+
+                            if let StatusType::Disabled(a) = modstatus {
+                                let botlock = bot.read().await;
+                                let outstr =
+                                    format!("sadg Module is disabled : {:?}",a);
+                                botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
+                                return;
+                            };
+
+
+                            
                             let eval = {
                                 let mut idlock = id.write().await;
                                 let (permissability, chngrslt) = idlock

From 582702fab23879b85c5a205d80d745ca6bf0b011 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 18:49:07 -0400
Subject: [PATCH 21/98] load botmodules module

---
 src/core/botmodules.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index df0595f..e790029 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -388,7 +388,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             trg_level, 
             force, 
             id).await;
-            
+
 
         let outmsg = match rslt.clone() {
             ChangeResult::Failed(a) => format!("Stare Failed : {}",a),
@@ -600,6 +600,7 @@ impl ModulesManager {
 
         // 1. load core modules
         crate::core::identity::init(Arc::clone(&mgrarc)).await;
+        crate::core::botmodules::init(Arc::clone(&mgrarc)).await;
 
         // 2. load custom modules
         crate::custom::init(Arc::clone(&mgrarc)).await;

From 2c298663b1ae519a4503d94196eab3aa2fb29dff Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 19:07:19 -0400
Subject: [PATCH 22/98] rsp only to elevated users

---
 src/core/botinstance.rs | 41 +++++++++++++++++++++++++++++++++--------
 1 file changed, 33 insertions(+), 8 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 5e70806..2f1548c 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -19,7 +19,7 @@ use crate::core::ratelimiter::RateLimiter;
 
 use crate::core::bot_actions::actions_util::BotAR;
 use crate::core::botmodules::ModulesManager;
-use crate::core::identity::{IdentityManager, Permissible};
+use crate::core::identity::{IdentityManager, Permissible,self};
 
 use crate::core::botlog;
 use crate::core::chat::Chat;
@@ -295,7 +295,7 @@ impl BotInstance {
                             let botlock = bot.read().await;
                             let id = botlock.get_identity();
 
-                            // [ ] Check first if the Module for that Given Command is Enabled or Disabled on the given Channel
+                            // [x] Check first if the Module for that Given Command is Enabled or Disabled on the given Channel
                             let modmgr = Arc::clone(&botlock.botmodules);
                             let modstatus = modmgr.modstatus(
                                 c.module.clone(), 
@@ -303,15 +303,40 @@ impl BotInstance {
 
 
                             if let StatusType::Disabled(a) = modstatus {
-                                let botlock = bot.read().await;
-                                let outstr =
-                                    format!("sadg Module is disabled : {:?}",a);
-                                botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
+
+                                // [x] Should only respond if a BotAdmin , Mod , SupMod , BroadCaster
+                                //    - Specifically it should respond only to those who may be able to enable the module
+
+                                
+                                const OF_CMD_CHANNEL:ChType = Channel(String::new());
+
+                                let elevated_access = {
+                                    let mut idlock = id.write().await;
+                                    let (permissability, _) = idlock
+                                        .can_user_run_prvmsg(msg, 
+                                            vec![
+                                                identity::UserRole::BotAdmin,
+                                                identity::UserRole::Mod(OF_CMD_CHANNEL),
+                                                identity::UserRole::SupMod(OF_CMD_CHANNEL),
+                                                identity::UserRole::Broadcaster,
+                                            ])
+                                        .await;
+    
+                                    permissability
+                                };
+
+                                if let Permissible::Allow = elevated_access {
+                                    let botlock = bot.read().await;
+                                    let outstr =
+                                        format!("sadg Module is disabled : {:?}",a);
+                                    botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
+                                } 
+
                                 return;
                             };
 
 
-                            
+
                             let eval = {
                                 let mut idlock = id.write().await;
                                 let (permissability, chngrslt) = idlock
@@ -350,7 +375,7 @@ impl BotInstance {
                             match eval {
                                 Permissible::Allow => {
                                     botlog::debug(
-                                        "Executed as permissible",
+                                        "Executing as permissible",
                                         Some("BotInstance > listener_main_prvmsg()".to_string()),
                                         Some(msg),
                                     );

From 4b0d51a6749d8c080c4b40ad64d665a57ec23075 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 19:50:25 -0400
Subject: [PATCH 23/98] listener modules validated

---
 src/core/botinstance.rs   | 64 +++++++++++++++++++++++++++++++++++++--
 src/custom/experiments.rs |  2 +-
 2 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 2f1548c..1452860 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -307,6 +307,12 @@ impl BotInstance {
                                 // [x] Should only respond if a BotAdmin , Mod , SupMod , BroadCaster
                                 //    - Specifically it should respond only to those who may be able to enable the module
 
+                                botlog::trace(
+                                    &format!("Identified cmd is associated with Disabled Module : StatusLvl = {:?}", a),
+                                    Some("BotInstance > listener_main_prvmsg()".to_string()),
+                                    Some(msg),
+                                );
+
                                 
                                 const OF_CMD_CHANNEL:ChType = Channel(String::new());
 
@@ -403,8 +409,62 @@ impl BotInstance {
                     }
 
                     crate::core::botmodules::BotAction::L(l) => {
-                        let a = Arc::clone(&bot);
-                        l.execute(a, msg.clone()).await;
+                        
+                        let botlock = bot.read().await;
+                        // let id = botlock.get_identity();
+
+                        // [x] Check first if the Module for that Given Command is Enabled or Disabled on the given Channel
+                        let modmgr = Arc::clone(&botlock.botmodules);
+                        let modstatus = modmgr.modstatus(
+                            l.module.clone(), 
+                            ChType::Channel(msg.channel_login.to_string())).await;
+
+
+                        if let StatusType::Disabled(a) = modstatus {
+
+                            // [x] Should only respond if a BotAdmin , Mod , SupMod , BroadCaster
+                            //    - Specifically it should respond only to those who may be able to enable the module
+
+                            botlog::trace(
+                                &format!("Identified listener is associated with Disabled Module : StatusLvl = {:?}", a),
+                                Some("BotInstance > listener_main_prvmsg()".to_string()),
+                                Some(msg),
+                            );
+
+                            
+                            // const OF_CMD_CHANNEL:ChType = Channel(String::new());
+
+                            // let elevated_access = {
+                            //     let mut idlock = id.write().await;
+                            //     let (permissability, _) = idlock
+                            //         .can_user_run_prvmsg(msg, 
+                            //             vec![
+                            //                 identity::UserRole::BotAdmin,
+                            //                 identity::UserRole::Mod(OF_CMD_CHANNEL),
+                            //                 identity::UserRole::SupMod(OF_CMD_CHANNEL),
+                            //                 identity::UserRole::Broadcaster,
+                            //             ])
+                            //         .await;
+
+                            //     permissability
+                            // };
+
+                            // if let Permissible::Allow = elevated_access {
+                            //     let botlock = bot.read().await;
+                            //     let outstr =
+                            //         format!("sadg Module is disabled : {:?}",a);
+                            //     botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
+                            // } 
+
+                            //return;
+                        } else {
+                            let a = Arc::clone(&bot);
+                            l.execute(a, msg.clone()).await;
+                        }
+
+
+                        // let a = Arc::clone(&bot);
+                        // l.execute(a, msg.clone()).await;
                     }
 
                     _ => (),
diff --git a/src/custom/experiments.rs b/src/custom/experiments.rs
index de2f424..529e551 100644
--- a/src/custom/experiments.rs
+++ b/src/custom/experiments.rs
@@ -125,7 +125,7 @@ async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
             Some(&msg),
         );
 
-        let rollwin = rand::thread_rng().gen_ratio(1, 8);
+        let rollwin = rand::thread_rng().gen_ratio(1, 1);
 
         if rollwin {
             botlog::debug(

From 06e182df556942bf852c35b024822552ad712e41 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 20:18:02 -0400
Subject: [PATCH 24/98] clippy adj

---
 src/core/botmodules.rs | 55 +++++++++++++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index e790029..d716ec5 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -44,6 +44,8 @@ use crate::core::bot_actions;
 pub use ChType::Channel;
 pub use ModType::BotModule;
 
+use std::hash::{Hash, Hasher};
+
 use super::identity::ChatBadge;
 
 // use super::identity::ChangeResult;
@@ -162,7 +164,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
 
         // if no trg_module was passed 
-        if let None = trg_module {
+        // if let None = trg_module {
+        if trg_module.is_none() {
 
             let botlock = bot.read().await;
             
@@ -190,8 +193,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let currchnl = msg.channel_login.to_lowercase();
 
         let trg_level = 
-            if arg1 == Some("-i") { StatusLvl::Instance } 
-            else if arg1 == Some("-f") { StatusLvl::Instance }
+            if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
+            // else if arg1 == Some("-f") { StatusLvl::Instance }
             else { StatusLvl::Ch(ChType::Channel(currchnl)) }
             ; 
 
@@ -338,7 +341,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
 
         // if no trg_module was passed 
-        if let None = trg_module {
+        // if let None = trg_module {
+        if trg_module.is_none() {
 
             let botlock = bot.read().await;
             
@@ -367,8 +371,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let currchnl = msg.channel_login.to_lowercase();
 
         let trg_level = 
-            if arg1 == Some("-i") { StatusLvl::Instance } 
-            else if arg1 == Some("-f") { StatusLvl::Instance }
+            if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
+            // else if arg1 == Some("-f") { StatusLvl::Instance }
             else { StatusLvl::Ch(ChType::Channel(currchnl)) }
             ; 
 
@@ -416,7 +420,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 // #[derive(Debug, PartialEq, Eq, Hash, Clone)]
-#[derive(Debug, Hash, Clone)]
+// #[derive(Debug, Hash, Clone)]
+#[derive(Debug, Clone)]
 pub enum ModType {
     BotModule(String),
 }
@@ -430,6 +435,15 @@ impl PartialEq for ModType {
 }
 impl Eq for ModType {}
 
+impl Hash for ModType{
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        // self.id.hash(state);
+        // self.phone.hash(state);
+        let BotModule(name) = self.clone();
+        name.to_lowercase().hash(state);
+    }
+}
+
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum ModGroup {
@@ -561,10 +575,13 @@ impl BotActionTrait for Listener {
 #[derive(Debug)]
 pub struct Routine {}
 
+type StatusdbEntry = (ModGroup, Vec<StatusType>);
+
 pub struct ModulesManager {
     // statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
     // statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<StatusType>>>>,
-    statusdb: Arc<RwLock<HashMap<ModType, (ModGroup, Vec<StatusType>)>>>,
+    // statusdb: Arc<RwLock<HashMap<ModType, (ModGroup, Vec<StatusType>)>>>,
+    statusdb: Arc<RwLock<HashMap<ModType, StatusdbEntry>>>,
     pub botactions: Arc<RwLock<HashMap<ModType, Vec<BotAction>>>>,
 }
 
@@ -783,7 +800,8 @@ impl ModulesManager {
         let modlist = self.moduleslist().await;
         let rslt =  modlist.get(&trg_module);
 
-        if let None = rslt {
+        // if let None = rslt {
+        if rslt.is_none() {
             return ChangeResult::Failed("Module doesn't exist".to_string());
         }
 
@@ -1034,7 +1052,7 @@ impl ModulesManager {
         let modlist = self.moduleslist().await;
         let rslt =  modlist.get(&trg_module);
 
-        if let None = rslt {
+        if rslt.is_none() {
             return ChangeResult::Failed("Module doesn't exist".to_string());
         }
 
@@ -1245,9 +1263,12 @@ impl ModulesManager {
                             if (*x == StatusType::Enabled(StatusLvl::Instance)) 
                             || (*x == StatusType::Disabled(StatusLvl::Instance)) {
                                 true
-                            } else if let StatusType::Enabled(StatusLvl::Ch(_)) = (*x).clone() {
-                                true
-                            } else {false}
+                            // } else if let StatusType::Enabled(StatusLvl::Ch(_)) = (*x).clone() {
+                            //     true
+                            // } else {false}
+                            } else {
+                                matches!((*x).clone(), StatusType::Enabled(StatusLvl::Ch(_)))
+                            }
                         ) 
                 {
                     statusvector.remove(index);
@@ -1903,10 +1924,10 @@ mod core_modulesmanager {
 
         modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
 
-        let in_module = match current_test_scenario {
-            // TestScenarios::ModuleDoesNotExist => BotModule("NonExisting_Module".to_string()),
-            _ => in_module,
-        };
+        // let in_module = match current_test_scenario {
+        //     // TestScenarios::ModuleDoesNotExist => BotModule("NonExisting_Module".to_string()),
+        //     _ => in_module,
+        // };
 
 
         /*

From 72ebd5193c4912c2f3bfbc9714c77df745f7bce1 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Fri, 22 Mar 2024 21:06:15 -0400
Subject: [PATCH 25/98] comments cleanup

---
 src/core/botinstance.rs |  31 +--
 src/core/botmodules.rs  | 418 +++-------------------------------------
 src/core/identity.rs    |  54 +-----
 3 files changed, 25 insertions(+), 478 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 1452860..1aa0e49 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -246,7 +246,7 @@ impl BotInstance {
                         /*
                         BotCommand handling -
                         - [x] Checks if the input message is a prefix with command name or alias
-                        - [ ] Validate User can run based on identityModule(From_Bot)::can_user_run(
+                        - [x] Validate User can run based on identityModule(From_Bot)::can_user_run(
                                                         _usr:String,
                                                         _channelname:ChType,
                                                         _chat_badge:ChatBadge,
@@ -431,40 +431,11 @@ impl BotInstance {
                                 Some(msg),
                             );
 
-                            
-                            // const OF_CMD_CHANNEL:ChType = Channel(String::new());
-
-                            // let elevated_access = {
-                            //     let mut idlock = id.write().await;
-                            //     let (permissability, _) = idlock
-                            //         .can_user_run_prvmsg(msg, 
-                            //             vec![
-                            //                 identity::UserRole::BotAdmin,
-                            //                 identity::UserRole::Mod(OF_CMD_CHANNEL),
-                            //                 identity::UserRole::SupMod(OF_CMD_CHANNEL),
-                            //                 identity::UserRole::Broadcaster,
-                            //             ])
-                            //         .await;
-
-                            //     permissability
-                            // };
-
-                            // if let Permissible::Allow = elevated_access {
-                            //     let botlock = bot.read().await;
-                            //     let outstr =
-                            //         format!("sadg Module is disabled : {:?}",a);
-                            //     botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
-                            // } 
-
-                            //return;
                         } else {
                             let a = Arc::clone(&bot);
                             l.execute(a, msg.clone()).await;
                         }
 
-
-                        // let a = Arc::clone(&bot);
-                        // l.execute(a, msg.clone()).await;
                     }
 
                     _ => (),
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index d716ec5..cef3b2f 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -22,10 +22,8 @@ Example
 use core::panic;
 
 use std::collections::HashMap;
-// use std::error::Error;
 use std::sync::Arc;
 
-// use futures::stream::iter;
 use twitch_irc::message::PrivmsgMessage;
 
 use casual_logger::Log;
@@ -48,8 +46,6 @@ use std::hash::{Hash, Hasher};
 
 use super::identity::ChatBadge;
 
-// use super::identity::ChangeResult;
-
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
@@ -91,7 +87,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         /*
 
             1. Parse out Message Arguments
-
             
             exec_enable()
 
@@ -415,12 +410,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 
-
-
-
-
-// #[derive(Debug, PartialEq, Eq, Hash, Clone)]
-// #[derive(Debug, Hash, Clone)]
 #[derive(Debug, Clone)]
 pub enum ModType {
     BotModule(String),
@@ -578,9 +567,6 @@ pub struct Routine {}
 type StatusdbEntry = (ModGroup, Vec<StatusType>);
 
 pub struct ModulesManager {
-    // statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
-    // statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<StatusType>>>>,
-    // statusdb: Arc<RwLock<HashMap<ModType, (ModGroup, Vec<StatusType>)>>>,
     statusdb: Arc<RwLock<HashMap<ModType, StatusdbEntry>>>,
     pub botactions: Arc<RwLock<HashMap<ModType, Vec<BotAction>>>>,
 }
@@ -668,19 +654,6 @@ impl ModulesManager {
                     StatusType::Enabled(StatusLvl::Instance)  // This forces core to be validated as Enabled, even if undesired scenario of missing StatusLvl::Instance or empty vectors
             },
             ModGroup::Custom  => {
-                // // remove all instance level pattern for the module
-                // while let Some(index) = statusvector
-                //         .iter()
-                //         .position(|x| (*x == StatusType::Enabled(StatusLvl::Instance)) || (*x == StatusType::Disabled(StatusLvl::Instance))) {
-
-                //             statusvector.remove(index);
-                //         }
-                // statusvector.push(StatusType::Disabled(StatusLvl::Instance));
-
-                // (
-                //     StatusType::Disabled(StatusLvl::Instance),
-                //     ChangeResult::Success("Set Disabled at Instance".to_string())
-                // )
 
                 /* 
                 
@@ -737,29 +710,12 @@ impl ModulesManager {
         //StatusType::Enabled(StatusLvl::Instance)
     }
 
-    // pub fn togglestatus(&self, _: ModType, _: ChType) -> StatusType {
-    //     // enables or disables based on current status
-    //     StatusType::Enabled(StatusLvl::Instance)
-    // }
-
-    // pub fn setstatus(&self, _: ModType, _: StatusType) -> Result<&str, Box<dyn Error>> {
-    //     // sets the status based given ModSatusType
-    //     // e.g., b.setstatus(BodModule("GambaCore"), Enabled(Channel("modulatingforce"))).expect("ERROR")
-    //     Ok("")
-    // }
-
-        /*
-        exec_enable(self,requestor,requestor_badge,trg_module,Channel) -> ChangeResult
-        */
-
     pub async fn exec_enable(
         &self,
         requestor: String,
         requestor_badge: Option<ChatBadge>,
         trg_module: ModType,
-        // channel: Option<ChType>,
         trg_level: StatusLvl,
-        // bot: BotAR,
         id: Arc<RwLock<IdentityManager>>,
     ) -> ChangeResult 
     {
@@ -784,7 +740,7 @@ impl ModulesManager {
 
 
          /*
-            [ ] 1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+            [x] 1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
                 1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
                     1a. , and is -i (to instance) , return a Success
                     1b. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
@@ -795,19 +751,14 @@ impl ModulesManager {
 
         // [x] Validate in trg_module first
 
-        // let botlock = bot.read().await;
-        // let modmgr = Arc::clone(&botlock.botmodules);
         let modlist = self.moduleslist().await;
         let rslt =  modlist.get(&trg_module);
 
-        // if let None = rslt {
         if rslt.is_none() {
             return ChangeResult::Failed("Module doesn't exist".to_string());
         }
 
 
-        // let botlock = bot.read().await;
-        // let id = botlock.get_identity();
         let mut idlock = id.write().await;
 
         // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
@@ -833,16 +784,6 @@ impl ModulesManager {
         ]).await;
 
 
-        // botlog::debug(
-        //     &format!("FAILURE BEFORE Let statements involves : 
-        //         admin_level_access : {:?} ; chnl_elevated_access : {:?}", 
-        //         admin_level_access , chnl_elevated_access),
-        //     Some("botmodules.rs > exec_enable()".to_string()),
-        //     None,
-        // );
-
-
-
         if let Permissible::Allow = admin_level_access {
             if let Permissible::Block = chnl_elevated_access {
                 
@@ -868,7 +809,7 @@ impl ModulesManager {
 
 
         /*
-            [ ] 2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+            [x] 2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
                 2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
                     2a. , and is -i (to instance) ,  return a Failure they are not allowed
                     2b. , and is not -i (to instance) , return a Success
@@ -892,7 +833,7 @@ impl ModulesManager {
 
         /*
         
-            [ ] 3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+            [x] 3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
                 3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
                     3a. , and is not -i (to instance) , return a Success
                     3b. , and is -i (to instance) , return a Success    
@@ -937,64 +878,11 @@ impl ModulesManager {
 
 
 
-
-
         // =======================
-
         // =======================
-
         // =======================
 
 
-        // /*
-        
-        //     2. Get Special Roles of CmdSender
-        //     3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster) 
-        //         3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
-        //         3b. , and is -i (to instance) , return a Success
-        //     4. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
-        //         4a. , and is not -i (to instance) , return a Success
-        //         4b. , and is -i (to instance) , return a Failure they are not allowed
-        //     5. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
-        //         5a. , and is not -i (to instance) , return a Success
-        //         5b. , and is -i (to instance) , return a Success
-
-        
-        // */
-
-        // // [ ] 2. Get Special Roles of CmdSender
-
-        // let botlock = bot.read().await;
-        // let id = botlock.get_identity();
-        // let idlock = id.read().await;
-
-
-        // let trgchnl = {
-        //     match trg_level {
-        //         StatusLvl::Instance => None,
-        //         StatusLvl::Ch(a) => Some(a),
-        //     }
-        // };
-
-        // let requestor_roles = idlock
-        //         .getspecialuserroles(
-        //             requestor.to_lowercase(),
-        //             trgchnl,
-        //         )
-        //         .await;
-
-        // /*
-        //     [ ] 3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster) 
-        //         3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
-        //         3b. , and is -i (to instance) , return a Success
-        //  */
-        
-        // if requestor_roles.contains(&identity::UserRole::BotAdmin) 
-        //     && !requestor_roles.contains(&identity::UserRole::Broadcaster)
-        //     && !requestor_roles.contains(&identity::UserRole::Mod(trgchnl)) 
-        // {
-
-        // } 
 
         botlog::debug(
             &format!("FAILURE involves : 
@@ -1016,10 +904,8 @@ impl ModulesManager {
         requestor: String,
         requestor_badge: Option<ChatBadge>,
         trg_module: ModType,
-        // channel: Option<ChType>,
         trg_level: StatusLvl,
         force: bool,
-        // bot: BotAR,
         id: Arc<RwLock<IdentityManager>>,
     ) -> ChangeResult 
     {
@@ -1047,8 +933,6 @@ impl ModulesManager {
 
         // [x] Validate in trg_module first
 
-        // let botlock = bot.read().await;
-        // let modmgr = Arc::clone(&botlock.botmodules);
         let modlist = self.moduleslist().await;
         let rslt =  modlist.get(&trg_module);
 
@@ -1057,9 +941,6 @@ impl ModulesManager {
         }
 
          
-
-        // let botlock = bot.read().await;
-        // let id = botlock.get_identity();
         let mut idlock = id.write().await;
 
         // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
@@ -1087,7 +968,7 @@ impl ModulesManager {
 
         /*
         
-            [ ] 1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
+            [x] 1. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
                 1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
                     1a. , and is -f (forced) , return a Success
                     1b. , and is -i (to instance) , return a Success
@@ -1116,11 +997,11 @@ impl ModulesManager {
 
 
         /*
-                [ ] 2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
-                    2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
-                        2a. , and is -f (forced) ,  return a Failure they are not allowed
-                        2b. , and is -i (to instance) ,  return a Failure they are not allowed
-                        2c. , and has no special flags (-i / -f) , return a Success
+            [x] 2. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster) 
+                2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) 
+                    2a. , and is -f (forced) ,  return a Failure they are not allowed
+                    2b. , and is -i (to instance) ,  return a Failure they are not allowed
+                    2c. , and has no special flags (-i / -f) , return a Success
 
          */
 
@@ -1144,11 +1025,11 @@ impl ModulesManager {
 
 
         /*
-                [ ] 3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
-                    3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
-                        3a. , and is -f (forced) , return a Success   
-                        3b. , and is -i (to instance) , return a Success
-                        3c. , and has no special flags (-i / -f) , return a Success
+            [x] 3. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin 
+                3. can_user_run for cmdreqRoles (Mod,SupMod,Broadcaster) & can_user_run for cmdreqRoles including BotAdmin
+                    3a. , and is -f (forced) , return a Success   
+                    3b. , and is -i (to instance) , return a Success
+                    3c. , and has no special flags (-i / -f) , return a Success
 
          */
 
@@ -1203,11 +1084,8 @@ impl ModulesManager {
         // at Instance level
         // - If core module, do nothing
 
-        // self.satusdb.
-
         let mut dbt = self.statusdb.write().await;
          
-        // let a = dbt.entry(in_module.clone()).;
         let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
 
         match mgrp {
@@ -1244,7 +1122,6 @@ impl ModulesManager {
 
         let mut dbt = self.statusdb.write().await;
          
-        // let a = dbt.entry(in_module.clone()).;
         let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
 
         match mgrp {
@@ -1263,9 +1140,6 @@ impl ModulesManager {
                             if (*x == StatusType::Enabled(StatusLvl::Instance)) 
                             || (*x == StatusType::Disabled(StatusLvl::Instance)) {
                                 true
-                            // } else if let StatusType::Enabled(StatusLvl::Ch(_)) = (*x).clone() {
-                            //     true
-                            // } else {false}
                             } else {
                                 matches!((*x).clone(), StatusType::Enabled(StatusLvl::Ch(_)))
                             }
@@ -1291,7 +1165,6 @@ impl ModulesManager {
 
         let mut dbt = self.statusdb.write().await;
          
-        // let a = dbt.entry(in_module.clone()).;
         let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
 
         match mgrp {
@@ -1328,7 +1201,6 @@ impl ModulesManager {
 
         let mut dbt = self.statusdb.write().await;
          
-        // let a = dbt.entry(in_module.clone()).;
         let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
 
         match mgrp {
@@ -1366,7 +1238,6 @@ impl ModulesManager {
 
         let mut dbt = self.statusdb.write().await;
          
-        // let a = dbt.entry(in_module.clone()).;
         let (mgrp,statusvector) = dbt.get_mut(&in_module).unwrap();
 
         match mgrp {
@@ -1506,17 +1377,6 @@ impl ModulesManager {
             )
         }
 
-        // let mut dbt = self.statusdb.write().await;
-        // // 
-        // let statusvector = dbt.entry(in_module.clone()).or_insert((in_modgroup.clone(),Vec::new()));
-
-        // match in_modgroup {
-        //     ModGroup::Core => statusvector.1.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
-        //     ModGroup::Custom => statusvector.1.push(StatusType::Disabled(StatusLvl::Instance)),
-        // }
-
-        // statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level
-
         self.affirm_in_statusdb(in_module.clone(),in_modgroup).await;
 
         let mut a = self.botactions.write().await;
@@ -1571,8 +1431,6 @@ mod core_modulesmanager {
     }
 
 
-
-
     /*
         Possible Tests
 
@@ -1862,20 +1720,8 @@ mod core_modulesmanager {
             // ModuleDoesNotExist, // preferring instead to handle in it's own smaller test
         }
 
-        
-        // let channel = ChType::Channel("somechannel".to_string());
-
-
-        // let mut idlock = idmgr.write().await;
         let mut idlock = idmgr.clone();
 
-        // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
-
-        // let arb_chnl = match trg_level.clone() {
-        //     StatusLvl::Instance => ChType::Channel(requestor.to_lowercase()),
-        //     StatusLvl::Ch(a) => a,
-        // };
-
         let requestor_badge = None; // If they are a Mod on the Given Channel already, that can be evaluated without the current badge
 
         const OF_CMD_CHANNEL:ChType = Channel(String::new());
@@ -1917,19 +1763,8 @@ mod core_modulesmanager {
         let in_module = BotModule("Experiments01".to_string());
         let in_modgroup = ModGroup::Custom;
 
-        // match current_test_scenario {
-        //     TestScenarios::BotadminUser => modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await,
-        //     _ => self::panic!("Scenario not handled"),
-        // }
-
         modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
 
-        // let in_module = match current_test_scenario {
-        //     // TestScenarios::ModuleDoesNotExist => BotModule("NonExisting_Module".to_string()),
-        //     _ => in_module,
-        // };
-
-
         /*
             [x] 3. affirm when BotAdmin attempts to exec_enable on the following
                     a. Channel Level , where they are not a Mod
@@ -1956,8 +1791,6 @@ mod core_modulesmanager {
             trg_level.clone(), 
             id.clone()).await;
 
-        // assert_eq!(rslt,ChangeResult::Failed("Promote yourself Temporarily First".to_string()));
-
         match current_test_scenario {
             TestScenarios::BotadminUser => 
                 assert_eq!(rslt,ChangeResult::Failed("Promote yourself Temporarily First".to_string())),
@@ -1965,10 +1798,6 @@ mod core_modulesmanager {
                 assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string())),
             TestScenarios::RegularChatter => 
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // TestScenarios::ModuleDoesNotExist => 
-            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         }
 
 
@@ -1978,7 +1807,7 @@ mod core_modulesmanager {
          */
 
         // [x] requestor_badge: Option<ChatBadge>,
-        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+        
         let requestor_badge =   match current_test_scenario {
             TestScenarios::BotadminUser => 
                 Some(ChatBadge::Mod), // setting badge to Mod -- for the Problem Scenario . They are both BotAdmin & Mod
@@ -1986,10 +1815,6 @@ mod core_modulesmanager {
                 Some(ChatBadge::Mod), // setting badge to Mod
             TestScenarios::RegularChatter => 
                 None, // setting badge to None
-            // TestScenarios::ModuleDoesNotExist => 
-            //     None,
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         } ;
         
 
@@ -1999,8 +1824,6 @@ mod core_modulesmanager {
             trg_level.clone(), 
             id.clone()).await;
 
-        // assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string()));
-
         match current_test_scenario {
             TestScenarios::BotadminUser => 
                 assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string())),
@@ -2008,10 +1831,6 @@ mod core_modulesmanager {
                 assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string())),
             TestScenarios::RegularChatter => 
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // TestScenarios::ModuleDoesNotExist => 
-            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),    
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         }
 
         /*
@@ -2028,10 +1847,6 @@ mod core_modulesmanager {
                 Some(ChatBadge::Mod),
             TestScenarios::RegularChatter => 
                 None, // setting badge to None
-            // TestScenarios::ModuleDoesNotExist => 
-            //     None, // setting badge to None
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         };
 
          let rslt = modsmgr.exec_enable(requestor.clone(), 
@@ -2040,7 +1855,6 @@ mod core_modulesmanager {
              trg_level.clone(), 
              id.clone()).await;
  
-        //  assert_eq!(rslt,ChangeResult::Success("Enabled at Instance Level".to_string()));
 
          match current_test_scenario {
             TestScenarios::BotadminUser => 
@@ -2049,10 +1863,6 @@ mod core_modulesmanager {
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
             TestScenarios::RegularChatter => 
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // TestScenarios::ModuleDoesNotExist => 
-            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         }
 
          /*
@@ -2069,7 +1879,6 @@ mod core_modulesmanager {
             false, 
             id.clone()).await;
 
-        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
         match current_test_scenario {
             TestScenarios::BotadminUser => 
                 assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
@@ -2077,10 +1886,6 @@ mod core_modulesmanager {
                 assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
             TestScenarios::RegularChatter => 
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // TestScenarios::ModuleDoesNotExist => 
-            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         }
 
 
@@ -2091,7 +1896,7 @@ mod core_modulesmanager {
 
           
         let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
-        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
+        
         let requestor_badge = match current_test_scenario {
             TestScenarios::BotadminUser => 
                 None,
@@ -2099,10 +1904,6 @@ mod core_modulesmanager {
                 Some(ChatBadge::Mod),
             TestScenarios::RegularChatter => 
                 None, // setting badge to None
-            // TestScenarios::ModuleDoesNotExist => 
-            //     None,
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         };
 
         let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
@@ -2112,7 +1913,7 @@ mod core_modulesmanager {
             false, 
             id.clone()).await;
 
-        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
+            
         match current_test_scenario {
             TestScenarios::BotadminUser => 
                 assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
@@ -2120,10 +1921,6 @@ mod core_modulesmanager {
                 assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string())),
             TestScenarios::RegularChatter => 
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // TestScenarios::ModuleDoesNotExist => 
-            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         }
 
 
@@ -2133,8 +1930,8 @@ mod core_modulesmanager {
           */
 
           let trg_level = StatusLvl::Instance; // setting to Instance level
-        //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
-  
+        
+        
           let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
               None, // Does not have a ChatBadge like Mod
               trg_module.clone(), 
@@ -2142,7 +1939,6 @@ mod core_modulesmanager {
               false, 
               id.clone()).await;
   
-        //   assert_eq!(rslt,ChangeResult::Success("Disabled at Instance Level".to_string()));
           match current_test_scenario {
             TestScenarios::BotadminUser => 
                 assert_eq!(rslt,ChangeResult::Success("Disabled at Instance Level".to_string())),
@@ -2150,10 +1946,6 @@ mod core_modulesmanager {
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
             TestScenarios::RegularChatter => 
                 assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // TestScenarios::ModuleDoesNotExist =>
-            //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-            // _ => 
-            //     self::panic!("Scenario not handled"),
         }
 
           /*
@@ -2162,7 +1954,6 @@ mod core_modulesmanager {
           */
 
           let trg_level = StatusLvl::Instance; // setting to Instance level
-          //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
     
             let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
                 None, // Does not have a ChatBadge like Mod
@@ -2171,7 +1962,6 @@ mod core_modulesmanager {
                 true, // force flag - true  
                 id.clone()).await;
     
-            // assert_eq!(rslt,ChangeResult::Success("Forced Disable".to_string()));
             match current_test_scenario {
                 TestScenarios::BotadminUser => 
                     assert_eq!(rslt,ChangeResult::Success("Forced Disable".to_string())),
@@ -2179,10 +1969,6 @@ mod core_modulesmanager {
                     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
                 TestScenarios::RegularChatter => 
                     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-                // TestScenarios::ModuleDoesNotExist => 
-                //     assert_eq!(rslt,ChangeResult::Failed("You're not allowed".to_string())),
-                // _ => 
-                //     self::panic!("Scenario not handled"),
             }
 
 
@@ -2214,14 +2000,6 @@ mod core_modulesmanager {
         let idmgr = IdentityManager::init();
         let modsmgr = ModulesManager::init().await;
 
-        // // [x] 2. modmgr.affirm_in_statusdb(Experiments01,Custom)
-
-        // let in_module = BotModule("Experiments01".to_string());
-        // let in_modgroup = ModGroup::Custom;
-
-        // modsmgr.affirm_in_statusdb(in_module.clone(), in_modgroup.clone()).await;
-
-
         /*
             [x] 3. affirm when BotAdmin attempts to exec_enable on the following
                     a. Channel Level , where they are not a Mod
@@ -2230,7 +2008,6 @@ mod core_modulesmanager {
         // [x] Create BotAdmin first
 
         let requestor = "botadministrator".to_string();
-        // let botadmin_badge = &None;
 
         idmgr.affirm_chatter_in_db(requestor.clone()).await;
         idmgr
@@ -2249,149 +2026,6 @@ mod core_modulesmanager {
         inner_enable_disable_complex(requestor, channel, idmgr, modsmgr).await;
 
 
-        /*
-            pub async fn exec_enable(
-                &self,
-                requestor: String,
-                requestor_badge: Option<ChatBadge>,
-                trg_module: ModType,
-                trg_level: StatusLvl,
-                id: Arc<RwLock<IdentityManager>>,
-            ) -> ChangeResult 
-
-         */
-
-        /*
-            [x] 3. affirm when BotAdmin attempts to exec_enable on the following
-                    a. Channel Level , where they are not a Mod
-        */
-
-
-        // [-] requestor_badge: Option<ChatBadge>,
-
-        // [x] trg_module: ModType,
-        // let trg_module = in_module;
-
-        // [x] trg_level: StatusLvl,
-
-        // let channel = ChType::Channel("somechannel".to_string());
-        // let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
-
-
-        // // [x] id: Arc<RwLock<IdentityManager>>,
-        // let id = Arc::new(RwLock::new(idmgr));
-
-
-        // let rslt = modsmgr.exec_enable(requestor.clone(), 
-        //     None, 
-        //     trg_module.clone(), 
-        //     trg_level.clone(), 
-        //     id.clone()).await;
-
-        // assert_eq!(rslt,ChangeResult::Failed("Promote yourself Temporarily First".to_string()));
-
-        // /*
-        //     [x] 3. affirm when BotAdmin attempts to exec_enable on the following
-        //             b. Channel Level , when they are a Mod
-        //  */
-
-        // // [x] requestor_badge: Option<ChatBadge>,
-        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
-
-        // let rslt = modsmgr.exec_enable(requestor.clone(), 
-        //     Some(requestor_badge), 
-        //     trg_module.clone(), 
-        //     trg_level.clone(), 
-        //     id.clone()).await;
-
-        // assert_eq!(rslt,ChangeResult::Success("Enabled at Channel Level".to_string()));
-
-        // /*
-        //     [x] 3. affirm when BotAdmin attempts to exec_enable on the following
-        //             c. Instance Level
-        //  */
-
-        //  let trg_level = StatusLvl::Instance; // setting to Instance level
-
-        //  let rslt = modsmgr.exec_enable(requestor.clone(), 
-        //      None, // setting them back to Non-Mod
-        //      trg_module.clone(), 
-        //      trg_level.clone(), 
-        //      id.clone()).await;
- 
-        //  assert_eq!(rslt,ChangeResult::Success("Enabled at Instance Level".to_string()));
-
-        //  /*
-        //     [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
-        //         a. Channel Level , where they are not a Mod
-        //   */
-
-        // let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
-
-        // let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
-        //     None, // Does not have a ChatBadge like Mod
-        //     trg_module.clone(), 
-        //     trg_level.clone(),
-        //     false, 
-        //     id.clone()).await;
-
-        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
-
-
-        //   /*
-        //     [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
-        //         b. Channel Level , when they are a Mod
-        //   */
-
-          
-        // let trg_level = StatusLvl::Ch(channel.clone()); // setting to Channel Level 
-        // let requestor_badge = ChatBadge::Mod; // setting badge to Mod
-
-        // let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
-        //     Some(requestor_badge), 
-        //     trg_module.clone(), 
-        //     trg_level.clone(),
-        //     false, 
-        //     id.clone()).await;
-
-        // assert_eq!(rslt,ChangeResult::Success("Disabled at Channel Level".to_string()));
-
-        //   /*
-        //     [x] 4. affirm when BotAdmin attempts to exec_disable on the following 
-        //         c. Instance Level
-        //   */
-
-        //   let trg_level = StatusLvl::Instance; // setting to Instance level
-        // //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
-  
-        //   let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
-        //       None, // Does not have a ChatBadge like Mod
-        //       trg_module.clone(), 
-        //       trg_level.clone(),
-        //       false, 
-        //       id.clone()).await;
-  
-        //   assert_eq!(rslt,ChangeResult::Success("Disabled at Instance Level".to_string()));
-
-        //   /*
-        //         [ ] 4. affirm when BotAdmin attempts to exec_disable on the following 
-        //             d. force disable
-        //   */
-
-        //   let trg_level = StatusLvl::Instance; // setting to Instance level
-        //   //   let requestor_badge = ChatBadge::Mod; // setting badge to Mod
-    
-        //     let rslt: ChangeResult = modsmgr.exec_disable(requestor.clone(), 
-        //         None, // Does not have a ChatBadge like Mod
-        //         trg_module.clone(), 
-        //         trg_level.clone(),
-        //         true, // force flag - true  
-        //         id.clone()).await;
-    
-        //     assert_eq!(rslt,ChangeResult::Success("Forced Disable".to_string()));
-  
-
-
 
      }
 
@@ -2475,15 +2109,11 @@ mod core_modulesmanager {
 
 
          let requestor = "regular_user".to_string();
-         // let botadmin_badge = &None;
          let channel = ChType::Channel("somechannel".to_string());
  
  
          idmgr.affirm_chatter_in_db(requestor.clone()).await;
-        //  idmgr
-        //      .add_role(requestor.clone(), identity::UserRole::Mod(channel.clone()))
-        //      .await;
- 
+
          let rslt = idmgr
              .getspecialuserroles(
                 requestor.clone(), 
@@ -2511,14 +2141,12 @@ mod core_modulesmanager {
 
 
          let requestor = "regular_user".to_string();
-         // let botadmin_badge = &None;
+         
          let channel = ChType::Channel("somechannel".to_string());
  
  
          idmgr.affirm_chatter_in_db(requestor.clone()).await;
-        //  idmgr
-        //      .add_role(requestor.clone(), identity::UserRole::Mod(channel.clone()))
-        //      .await;
+         
  
          let rslt = idmgr
              .getspecialuserroles(
@@ -2555,7 +2183,7 @@ mod core_modulesmanager {
 
         assert_eq!(rslt,ChangeResult::Failed("Module doesn't exist".to_string()));
 
-        // [ ] Test with Non Existing module > disable
+        // [x] Test with Non Existing module > disable
 
         let trg_module = BotModule("Non_Existent_Module".to_string());
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index accda4f..0a27b60 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -696,59 +696,6 @@ impl IdentityManager {
             }
         }
 
-        // if &msg.badges.contains(Badge{}) {
-
-        // }
-
-        // if let Some(sender_badge) = sender_badge {
-        // match sender_badge {
-        //     Some(sender_badge) => {
-        // return &self.can_user_run(msg.sender.name.to_owned(),
-        //     ChType::Channel(msg.channel_login.to_owned()),
-        //     sender_badge,
-        //     cmdreqroles
-        // return self.can_user_run(msg.sender.name.to_owned(),
-        // let a = Arc::new(Mutex::new(self));
-        // let mut a = a.lock().await;
-        // let a = **a;
-        // let a = a.can_user_run(msg.sender.name.to_owned(),
-        // ChType::Channel(msg.channel_login.to_owned()),
-        // sender_badge,
-        // cmdreqroles
-        //  ) ;
-        // let a = *self;
-        // let a = Arc::new(Mutex::new(a));
-        // let a = a.lock().await.can_user_run(msg.sender.name.to_owned(),
-        //                         ChType::Channel(msg.channel_login.to_owned()),
-        //                         sender_badge,
-        //                                     cmdreqroles
-        //                                     ) ;
-        // return a;
-        // return self.can_user_run(msg.sender.name.to_owned(),
-        //                         ChType::Channel(msg.channel_login.to_owned()),
-        //                         sender_badge,
-        //                                     cmdreqroles
-        //                                     ).await
-
-        // * NOTE : We're preferring to pass the ChangeResult up , where we have access to Chat via BotInstance
-        //   that have more strained chatting rules
-        //     let evalpermissible = self.can_user_run(msg.sender.name.to_owned(),
-        //                             ChType::Channel(msg.channel_login.to_owned()),
-        //                             sender_badge,
-        //                                         cmdreqroles
-        //                                         ).await ;
-        //                                         evalpermissible
-        // // }
-        // None => {
-
-        // }
-        // here , sender_badge is likely None
-        // This could be a regular chatter, BotAdmin,SupserMod
-
-        // [ ] Call can_user_run()
-        // (self,Permissible::Block)
-        // (Permissible::Block,ChangeResult::NoChange("".to_string()))
-
         self.can_user_run(
             msg.sender.name.to_owned(),
             ChType::Channel(msg.channel_login.to_owned()),
@@ -756,6 +703,7 @@ impl IdentityManager {
             cmdreqroles,
         )
         .await
+        
     }
 
     pub async fn can_user_run(

From 2957f9462bf4b33e2e20bf3a016848e3f3e60782 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 12:14:51 -0400
Subject: [PATCH 26/98] reorg common say logic

---
 src/core/chat.rs | 71 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 59 insertions(+), 12 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index fe49896..cc62376 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -27,6 +27,14 @@ pub struct Chat {
     pub client: TwitchIRCClient<TCPTransport<TLS>, StaticLoginCredentials>,
 }
 
+
+#[derive(Clone)]
+enum BotMsgType<'a> {
+    SayInReplyTo(&'a PrivmsgMessage,String),
+    _Say(String,String)
+}
+
+
 impl Chat {
     pub fn init(
         ratelimiters: HashMap<ChType, RateLimiter>,
@@ -43,8 +51,11 @@ impl Chat {
         self.ratelimiters.lock().await.insert(chnl, n);
     }
 
-    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, mut outmsg: String) {
-        /*
+
+
+
+    async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
+                /*
         formats message before sending to TwitchIRC
 
         - [x] Custom String Formatting (e.g., adding random black spaces)
@@ -53,12 +64,21 @@ impl Chat {
 
          */
 
+        let (channel_login,mut outmsg) = match msginput.clone() {
+            BotMsgType::SayInReplyTo(msg, outmsg) => {
+                (msg.channel_login.clone(),outmsg)
+            },
+            _ => {
+                panic!("ISSUE : NOT IMPLEMENTED")
+            },
+        };
+
         let rl = Arc::clone(&self.ratelimiters);
         let mut rllock = rl.lock().await;
 
         let contextratelimiter = rllock
             // .get_mut()
-            .get_mut(&Channel(String::from(&msg.channel_login)))
+            .get_mut(&Channel(String::from(channel_login.clone())))
             .expect("ERROR: Issue with Rate limiters");
 
         // Continue to check the limiter and sleep if required if the minimum is not reached
@@ -75,20 +95,38 @@ impl Chat {
                     outmsg.push_str(blankspace);
                 }
 
-                self.client.say_in_reply_to(msg, outmsg).await.unwrap();
-
+                match msginput.clone() {
+                    BotMsgType::SayInReplyTo(msg, _) => {
+                        self.client.say_in_reply_to(msg, outmsg).await.unwrap();
+                    },
+                    _ => {
+                        panic!("ISSUE : NOT IMPLEMENTED")
+                    },
+                }
+                
                 contextratelimiter.increment_counter();
 
                 let logstr = format!(
                     "(#{}) > {} ; contextratelimiter : {:?}",
-                    msg.channel_login, "rate limit counter increase", contextratelimiter
+                    channel_login.clone(), "rate limit counter increase", contextratelimiter
                 );
 
-                botlog::trace(
-                    logstr.as_str(),
-                    Some("Chat > say_in_reply_to".to_string()),
-                    Some(msg),
-                );
+                if let BotMsgType::SayInReplyTo(msg,_ ) = msginput {
+                    botlog::trace(
+                        logstr.as_str(),
+                        Some("Chat > say_in_reply_to".to_string()),
+                        Some(&msg),
+                    );
+                } else {
+                    botlog::trace(
+                        logstr.as_str(),
+                        Some("Chat > say_in_reply_to".to_string()),
+                        None,
+                    );
+                }
+
+
+
             }
             ratelimiter::LimiterResp::Skip => {
                 // (); // do nothing otherwise
@@ -98,7 +136,16 @@ impl Chat {
             }
         }
 
-        Log::flush();
+ 
+         Log::flush();
+    }
+
+
+
+    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
+
+        self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg)).await;
+
     }
 
     async fn _say(&self, _: String, _: String) {

From b8bf2e33f6ac2e33be12fca56f8423a99ddd04bd Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 12:21:08 -0400
Subject: [PATCH 27/98] added say to Chat

---
 src/core/chat.rs | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index cc62376..5ca8a61 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -31,7 +31,7 @@ pub struct Chat {
 #[derive(Clone)]
 enum BotMsgType<'a> {
     SayInReplyTo(&'a PrivmsgMessage,String),
-    _Say(String,String)
+    Say(String,String),
 }
 
 
@@ -68,9 +68,12 @@ impl Chat {
             BotMsgType::SayInReplyTo(msg, outmsg) => {
                 (msg.channel_login.clone(),outmsg)
             },
-            _ => {
-                panic!("ISSUE : NOT IMPLEMENTED")
+            BotMsgType::Say(a,b ) => {
+                (a.clone(),b.clone())
             },
+            // _ => {
+            //     panic!("ISSUE : NOT IMPLEMENTED")
+            // },
         };
 
         let rl = Arc::clone(&self.ratelimiters);
@@ -99,9 +102,12 @@ impl Chat {
                     BotMsgType::SayInReplyTo(msg, _) => {
                         self.client.say_in_reply_to(msg, outmsg).await.unwrap();
                     },
-                    _ => {
-                        panic!("ISSUE : NOT IMPLEMENTED")
-                    },
+                    BotMsgType::Say(a, _) => {
+                        self.client.say(a, outmsg).await.unwrap();
+                    }
+                    // _ => {
+                    //     panic!("ISSUE : NOT IMPLEMENTED")
+                    // },
                 }
                 
                 contextratelimiter.increment_counter();
@@ -114,13 +120,13 @@ impl Chat {
                 if let BotMsgType::SayInReplyTo(msg,_ ) = msginput {
                     botlog::trace(
                         logstr.as_str(),
-                        Some("Chat > say_in_reply_to".to_string()),
+                        Some("Chat > send_botmsg".to_string()),
                         Some(&msg),
                     );
                 } else {
                     botlog::trace(
                         logstr.as_str(),
-                        Some("Chat > say_in_reply_to".to_string()),
+                        Some("Chat > send_botmsg".to_string()),
                         None,
                     );
                 }
@@ -148,10 +154,11 @@ impl Chat {
 
     }
 
-    async fn _say(&self, _: String, _: String) {
+    async fn _say(&self, channel_login: String, message: String) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
         // self.client.say(msg,outmsg).await.unwrap();
+        self.send_botmsg(BotMsgType::Say(channel_login, message)).await;
     }
 
     async fn _me(&self, _: String, _: String) {

From 5802e9b755d071be13837e669b6063706bd95d82 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 13:32:22 -0400
Subject: [PATCH 28/98] experimental say functionality

---
 src/core/chat.rs                              |  11 +-
 src/custom.rs                                 |   8 +-
 src/custom/experimental.rs                    |  24 ++++
 .../experiment001.rs}                         |   0
 src/custom/experimental/experiment002.rs      | 135 ++++++++++++++++++
 5 files changed, 172 insertions(+), 6 deletions(-)
 create mode 100644 src/custom/experimental.rs
 rename src/custom/{experiments.rs => experimental/experiment001.rs} (100%)
 create mode 100644 src/custom/experimental/experiment002.rs

diff --git a/src/core/chat.rs b/src/core/chat.rs
index 5ca8a61..7f00a7e 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -79,9 +79,15 @@ impl Chat {
         let rl = Arc::clone(&self.ratelimiters);
         let mut rllock = rl.lock().await;
 
+        botlog::debug(
+            &format!("Ratelimiter being checked for channel : {}",channel_login.clone()),
+            Some("Chat > send_botmsg".to_string()),
+            None,
+        );
+
         let contextratelimiter = rllock
             // .get_mut()
-            .get_mut(&Channel(String::from(channel_login.clone())))
+            .get_mut(&Channel(String::from(channel_login.to_lowercase().clone())))
             .expect("ERROR: Issue with Rate limiters");
 
         // Continue to check the limiter and sleep if required if the minimum is not reached
@@ -154,10 +160,9 @@ impl Chat {
 
     }
 
-    async fn _say(&self, channel_login: String, message: String) {
+    pub async fn say(&self, channel_login: String, message: String) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
-        // self.client.say(msg,outmsg).await.unwrap();
         self.send_botmsg(BotMsgType::Say(channel_login, message)).await;
     }
 
diff --git a/src/custom.rs b/src/custom.rs
index fc802e6..6107797 100644
--- a/src/custom.rs
+++ b/src/custom.rs
@@ -1,5 +1,5 @@
 /*
-    `modules` will :
+    `custom` will :
     - be a starting refrence point for the bot instance to pull module definitions for
 
 */
@@ -11,7 +11,8 @@ pub use crate::core::botmodules::ModulesManager;
 
 // [ ] Load submodules
 
-mod experiments;
+// mod experiments;
+mod experimental;
 
 // [ ] init() function that accepts bot instance - this is passed to init() on submodules
 
@@ -19,5 +20,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // Modules initializer loads modules into the bot
     // this is achieved by calling submodules that also have fn init() defined
 
-    experiments::init(mgr).await
+    // experiments::init(mgr).await
+    experimental::init(mgr).await;
 }
diff --git a/src/custom/experimental.rs b/src/custom/experimental.rs
new file mode 100644
index 0000000..e2aa67e
--- /dev/null
+++ b/src/custom/experimental.rs
@@ -0,0 +1,24 @@
+/*
+    `experimental` will :
+    - be for mostly experimental
+*/
+
+use std::sync::Arc;
+
+pub use crate::core::botinstance::BotInstance;
+pub use crate::core::botmodules::ModulesManager;
+
+// [ ] Load submodules
+
+mod experiment001;
+mod experiment002;
+
+// [ ] init() function that accepts bot instance - this is passed to init() on submodules
+
+pub async fn init(mgr: Arc<ModulesManager>) {
+    // Modules initializer loads modules into the bot
+    // this is achieved by calling submodules that also have fn init() defined
+
+    experiment001::init(Arc::clone(&mgr)).await;
+    experiment002::init(Arc::clone(&mgr)).await;
+}
diff --git a/src/custom/experiments.rs b/src/custom/experimental/experiment001.rs
similarity index 100%
rename from src/custom/experiments.rs
rename to src/custom/experimental/experiment001.rs
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
new file mode 100644
index 0000000..d3b70e5
--- /dev/null
+++ b/src/custom/experimental/experiment002.rs
@@ -0,0 +1,135 @@
+/*
+    Custom Modules -
+
+    Usage :
+    [ ] within the file's init(), define BotActions & Load them into the ModulesManager
+    [ ] Define Execution Bodies for these BotActions
+    [ ] Afterwards, add  the following to parent modules.rs file
+        - mod <modulename>;
+        - within init(), <modulename>::init(mgr).await
+
+*/
+
+// use rand::Rng;
+use std::sync::Arc;
+
+use twitch_irc::message::PrivmsgMessage;
+
+// use crate::core::botinstance::ChType::Channel;
+use crate::core::botinstance::ChType;
+use ChType::Channel;
+use crate::core::botlog;
+
+use casual_logger::Log;
+
+use crate::core::bot_actions::actions_util::{self, BotAR};
+use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
+
+use crate::core::identity::UserRole::*;
+
+// use tokio::time::{sleep, Duration};
+
+pub async fn init(mgr: Arc<ModulesManager>) {
+
+    const OF_CMD_CHANNEL:ChType = Channel(String::new());
+
+
+    // 1. Define the BotAction
+    let botc1 = BotCommand {
+        module: BotModule(String::from("experiments002")),
+        command: String::from("say"), // command call name
+        alias: vec![
+            "s".to_string(),
+        ], // String of alternative names
+        exec_body: actions_util::asyncbox(sayout),
+        help: String::from("Test Command tester"),
+        required_roles: vec![
+            BotAdmin,
+            Mod(OF_CMD_CHANNEL),
+        ], 
+    };
+
+    // 2. Add the BotAction to ModulesManager
+    botc1.add_to_modmgr(Arc::clone(&mgr)).await;
+
+    mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await;
+
+
+}
+
+
+async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
+
+    /*
+        usage :
+        <target channel> <message>
+     */
+
+    // [x] Unwraps arguments from message
+
+    let argrslt = 
+        if let Some((_,str1)) = msg.message_text.split_once(" ") {
+            if let Some((channelstr,msgstr)) = str1.split_once(" ") {
+                // println!("{}",cmdstr);
+                // println!("{}",channelstr);
+                // println!("{}",msgstr);
+                Some((channelstr,msgstr))
+            } 
+            else { None }
+        }
+        else { None };
+
+    
+
+
+    match argrslt {
+        Some((trgchnl,outmsg)) => {
+
+            let newoutmsg = format!("{} (from #{}) says : {}",
+                msg.sender.name,msg.channel_login, outmsg);
+
+
+            let bot = Arc::clone(&bot);
+
+            let botlock = bot.read().await;
+
+            // uses chat.say_in_reply_to() for the bot controls for messages
+            botlock
+                .botmgrs
+                .chat
+                .say(trgchnl.to_string(), newoutmsg.to_string())
+                .await;
+
+            // botlog::debug(
+            //         "Sayout had issues trying to parse arguments",
+            //         Some("experiment002 > sayout".to_string()),
+            //         Some(&msg),
+            //     );
+
+
+        },
+        None => {
+            botlog::debug(
+                "sayout had issues trying to parse arguments",
+                Some("experiment002 > sayout".to_string()),
+                Some(&msg),
+            );
+
+            let bot = Arc::clone(&bot);
+
+            let botlock = bot.read().await;
+
+            // uses chat.say_in_reply_to() for the bot controls for messages
+            botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(&msg, String::from("Invalid arguments"))
+                .await;
+
+        },
+
+    }
+
+
+    Log::flush();
+}
\ No newline at end of file

From 960cd5724c1c3d533d0c43d44e07ab309724623f Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Fri, 22 Mar 2024 16:55:56 -0300
Subject: [PATCH 29/98] Simplifying enums

I hope this doesn't explode everything Prayge
---
 src/core/botinstance.rs   |  24 ++++---
 src/core/botmodules.rs    | 133 +++++++++++++++++++-------------------
 src/core/chat.rs          |  10 +--
 src/core/identity.rs      |  86 ++++++++++++------------
 src/custom/experiments.rs |   5 +-
 5 files changed, 132 insertions(+), 126 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 1aa0e49..a668dac 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -35,11 +35,15 @@ pub enum ChangeResult {
 
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
-pub enum ChType {
-    Channel(String),
-}
 
-pub use ChType::Channel;
+// pub enum ChType {
+//     Channel(String),
+// }
+//
+// pub use ChType::Channel;
+//
+//simplifying from enum to struct
+pub struct Channel(pub String);
 
 use super::botmodules::StatusType;
 
@@ -51,7 +55,7 @@ pub struct BotManagers {
 
 impl BotManagers {
     pub fn init(
-        ratelimiters: HashMap<ChType, RateLimiter>,
+        ratelimiters: HashMap<Channel, RateLimiter>,
         client: TwitchIRCClient<TCPTransport<TLS>, StaticLoginCredentials>,
     ) -> BotManagers {
         BotManagers {
@@ -75,11 +79,11 @@ impl<T: Clone> ArcBox<T> {
 
 pub struct BotInstance {
     pub prefix: char,
-    pub bot_channel: ChType,
+    pub bot_channel: Channel,
     pub incoming_messages: Arc<RwLock<UnboundedReceiver<ServerMessage>>>,
     pub botmodules: Arc<ModulesManager>,
     pub twitch_oauth: String,
-    pub bot_channels: Vec<ChType>,
+    pub bot_channels: Vec<Channel>,
     pub botmgrs: BotManagers,
     //modesmgr : ModesManager, // [FUTURE] Silent/Quiet , uwu , frisky/horny
 }
@@ -299,7 +303,7 @@ impl BotInstance {
                             let modmgr = Arc::clone(&botlock.botmodules);
                             let modstatus = modmgr.modstatus(
                                 c.module.clone(), 
-                                ChType::Channel(msg.channel_login.to_string())).await;
+                                Channel(msg.channel_login.to_string())).await;
 
 
                             if let StatusType::Disabled(a) = modstatus {
@@ -314,7 +318,7 @@ impl BotInstance {
                                 );
 
                                 
-                                const OF_CMD_CHANNEL:ChType = Channel(String::new());
+                                const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
                                 let elevated_access = {
                                     let mut idlock = id.write().await;
@@ -417,7 +421,7 @@ impl BotInstance {
                         let modmgr = Arc::clone(&botlock.botmodules);
                         let modstatus = modmgr.modstatus(
                             l.module.clone(), 
-                            ChType::Channel(msg.channel_login.to_string())).await;
+                            Channel(msg.channel_login.to_string())).await;
 
 
                         if let StatusType::Disabled(a) = modstatus {
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index cef3b2f..9c7152f 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -3,12 +3,12 @@
 ModulesManager is used to manage Modules and BotActions associated with those modules
 
 pub struct ModulesManager {
-    statusdb: HashMap<ModType,Vec<ModStatusType>>,
-    botactions: HashMap<ModType,Vec<BotAction>>,
+    statusdb: HashMap<BotModule,Vec<ModStatusType>>,
+    botactions: HashMap<BotModule,Vec<BotAction>>,
 }
 
-- statusdb: HashMap<ModType,Vec<ModStatusType>> - Defines Modules and their ModStatusType (e.g., Enabled at an Instance level, Disabled at a Channel Level)
-- botactions: HashMap<ModType,Vec<BotAction>> - Defines Modules and their BotActions (e.g., BotCommand , Listener, Routine)
+- statusdb: HashMap<BotModule,Vec<ModStatusType>> - Defines Modules and their ModStatusType (e.g., Enabled at an Instance level, Disabled at a Channel Level)
+- botactions: HashMap<BotModule,Vec<BotAction>> - Defines Modules and their BotActions (e.g., BotCommand , Listener, Routine)
 
 Example
     {
@@ -34,13 +34,13 @@ use async_trait::async_trait;
 
 use self::bot_actions::actions_util::BotAR;
 use crate::core::bot_actions::actions_util;
-use crate::core::botinstance::{BotInstance, ChType,ChangeResult};
+use crate::core::botinstance::{BotInstance, Channel,ChangeResult};
 use crate::core::botlog;
 use crate::core::identity::{self, Permissible,IdentityManager};
 
 use crate::core::bot_actions;
-pub use ChType::Channel;
-pub use ModType::BotModule;
+
+//pub use BotModule;
 
 use std::hash::{Hash, Hasher};
 
@@ -49,7 +49,7 @@ use super::identity::ChatBadge;
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:ChType = Channel(String::new());
+    const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
     // 1. Define the BotAction
     let botc1 = BotCommand {
@@ -126,8 +126,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 &self,
                 requestor: String,
                 requestor_badge: Option<ChatBadge>,
-                trg_module: ModType,
-                // channel: Option<ChType>,
+                trg_module: BotModule,
+                // channel: Option<Channel>,
                 trg_level: StatusLvl,
                 bot: BotAR,
             ) -> ChangeResult 
@@ -153,8 +153,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let requestor_badge = requestor_badge_mut;
 
 
-        // [x] trg_module: ModType,
-        //      - [x] Need to validate an actual ModType - otherwise, fail or exit the cmd
+        // [x] trg_module: BotModule,
+        //      - [x] Need to validate an actual BotModule - otherwise, fail or exit the cmd
     
         let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
 
@@ -190,7 +190,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let trg_level = 
             if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
             // else if arg1 == Some("-f") { StatusLvl::Instance }
-            else { StatusLvl::Ch(ChType::Channel(currchnl)) }
+            else { StatusLvl::Ch(Channel(currchnl)) }
             ; 
 
         
@@ -204,7 +204,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let rslt = modmgr.exec_enable(
             requestor, 
             requestor_badge, 
-            ModType::BotModule(trg_module.unwrap().to_string()), 
+            BotModule(trg_module.unwrap().to_string()), 
             trg_level, 
             id).await;
 
@@ -302,8 +302,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 &self,
                 requestor: String,
                 requestor_badge: Option<ChatBadge>,
-                trg_module: ModType,
-                // channel: Option<ChType>,
+                trg_module: BotModule,
+                // channel: Option<Channel>,
                 trg_level: StatusLvl,
                 force: bool,
                 // bot: BotAR,
@@ -330,8 +330,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let requestor_badge = requestor_badge_mut;
 
-                // [x] trg_module: ModType,
-        //      - [x] Need to validate an actual ModType - otherwise, fail or exit the cmd
+                // [x] trg_module: BotModule,
+        //      - [x] Need to validate an actual BotModule - otherwise, fail or exit the cmd
     
         let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
 
@@ -368,7 +368,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let trg_level = 
             if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
             // else if arg1 == Some("-f") { StatusLvl::Instance }
-            else { StatusLvl::Ch(ChType::Channel(currchnl)) }
+            else { StatusLvl::Ch(Channel(currchnl)) }
             ; 
 
 
@@ -383,7 +383,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let rslt = modmgr.exec_disable(
             requestor, 
             requestor_badge, 
-            ModType::BotModule(trg_module.unwrap().to_string()), 
+            BotModule(trg_module.unwrap().to_string()), 
             trg_level, 
             force, 
             id).await;
@@ -411,20 +411,23 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 #[derive(Debug, Clone)]
-pub enum ModType {
-    BotModule(String),
-}
+// pub enum BotModule {
+//     BotModule(String),
+// }
 
-impl PartialEq for ModType {
+pub struct BotModule(pub String);
+//botmodule simplified from enum to tuple struct
+
+impl PartialEq for BotModule {
     fn eq(&self, other: &Self) -> bool {
         let BotModule(name1) = self.clone();
         let BotModule(name2) = other.clone();
         name1.to_lowercase() == name2.to_lowercase()
     }
 }
-impl Eq for ModType {}
+impl Eq for BotModule {}
 
-impl Hash for ModType{
+impl Hash for BotModule{
     fn hash<H: Hasher>(&self, state: &mut H) {
         // self.id.hash(state);
         // self.phone.hash(state);
@@ -443,7 +446,7 @@ pub enum ModGroup {
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub enum StatusLvl {
     Instance,
-    Ch(ChType),
+    Ch(Channel),
 }
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
@@ -477,7 +480,7 @@ pub trait BotActionTrait {
 }
 
 pub struct BotCommand {
-    pub module: ModType,
+    pub module: BotModule,
     pub command: String,    // command call name
     pub alias: Vec<String>, // String of alternative names
     pub exec_body: bot_actions::actions_util::ExecBody,
@@ -515,7 +518,7 @@ impl BotActionTrait for BotCommand {
 }
 
 pub struct Listener {
-    pub module: ModType,
+    pub module: BotModule,
     pub name: String,
     pub exec_body: bot_actions::actions_util::ExecBody,
     pub help: String,
@@ -567,20 +570,20 @@ pub struct Routine {}
 type StatusdbEntry = (ModGroup, Vec<StatusType>);
 
 pub struct ModulesManager {
-    statusdb: Arc<RwLock<HashMap<ModType, StatusdbEntry>>>,
-    pub botactions: Arc<RwLock<HashMap<ModType, Vec<BotAction>>>>,
+    statusdb: Arc<RwLock<HashMap<BotModule, StatusdbEntry>>>,
+    pub botactions: Arc<RwLock<HashMap<BotModule, Vec<BotAction>>>>,
 }
 
 /*
 
 statusdb
     <HashMap
-        <ModType, <-- e.g., BotModule(String::from("experiments001"))
+        <BotModule, <-- e.g., BotModule(String::from("experiments001"))
         Vec<ModStatusType> <-- shows Enabled/Disabled per Status level
 
 botactions
     HashMap<
-        ModType, <-- e.g.,  BotModule(String::from("experiments001"))
+        BotModule, <-- e.g.,  BotModule(String::from("experiments001"))
         Vec<BotAction>> BotCommand, Listener
 
 */
@@ -618,7 +621,7 @@ impl ModulesManager {
     }
 
 
-    pub async fn moduleslist(&self) -> HashMap<ModType,ModGroup>
+    pub async fn moduleslist(&self) -> HashMap<BotModule,ModGroup>
     {
 
         // let db = Arc::clone(&self.statusdb);
@@ -635,7 +638,7 @@ impl ModulesManager {
         outmap
     }
 
-    pub async fn modstatus(&self, in_module: ModType, in_chnl: ChType) -> StatusType {
+    pub async fn modstatus(&self, in_module: BotModule, in_chnl: Channel) -> StatusType {
         // Example usage : botmanager.modstatus(
         //     BotModule("GambaCore"),
         //     Channel("modulatingforce")
@@ -714,7 +717,7 @@ impl ModulesManager {
         &self,
         requestor: String,
         requestor_badge: Option<ChatBadge>,
-        trg_module: ModType,
+        trg_module: BotModule,
         trg_level: StatusLvl,
         id: Arc<RwLock<IdentityManager>>,
     ) -> ChangeResult 
@@ -764,11 +767,11 @@ impl ModulesManager {
         // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
 
         let arb_chnl = match trg_level.clone() {
-            StatusLvl::Instance => ChType::Channel(requestor.to_lowercase()),
+            StatusLvl::Instance => Channel(requestor.to_lowercase()),
             StatusLvl::Ch(a) => a,
         };
 
-        const OF_CMD_CHANNEL:ChType = Channel(String::new());
+        const OF_CMD_CHANNEL:Channel = Channel(String::new());
         
         let (admin_level_access,_) = idlock.can_user_run(requestor.clone(), arb_chnl.clone(), requestor_badge.clone(), 
         vec![
@@ -903,7 +906,7 @@ impl ModulesManager {
         &self,
         requestor: String,
         requestor_badge: Option<ChatBadge>,
-        trg_module: ModType,
+        trg_module: BotModule,
         trg_level: StatusLvl,
         force: bool,
         id: Arc<RwLock<IdentityManager>>,
@@ -946,11 +949,11 @@ impl ModulesManager {
         // if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
 
         let arb_chnl = match trg_level.clone() {
-            StatusLvl::Instance => ChType::Channel(requestor.to_lowercase()),
+            StatusLvl::Instance => Channel(requestor.to_lowercase()),
             StatusLvl::Ch(a) => a,
         };
 
-        const OF_CMD_CHANNEL:ChType = Channel(String::new());
+        const OF_CMD_CHANNEL:Channel = Channel(String::new());
         
         let (admin_level_access,_) = idlock.can_user_run(requestor.clone(), arb_chnl.clone(), requestor_badge.clone(), 
         vec![
@@ -1080,7 +1083,7 @@ impl ModulesManager {
          ChangeResult::Failed("ERROR : Not implemented yet".to_string())
     }
 
-    pub async fn set_instance_disabled(&self, in_module: ModType) -> (StatusType,ChangeResult) {
+    pub async fn set_instance_disabled(&self, in_module: BotModule) -> (StatusType,ChangeResult) {
         // at Instance level
         // - If core module, do nothing
 
@@ -1115,7 +1118,7 @@ impl ModulesManager {
         // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub async fn force_disable(&self, in_module: ModType) -> (StatusType,ChangeResult) {
+    pub async fn force_disable(&self, in_module: BotModule) -> (StatusType,ChangeResult) {
         // Disables the module at Instance level, and removes all Enabled at Channel level
         //  - Bot Moderators MUST Re-enable if they were enabled before
         //  - If core module, do nothing
@@ -1159,7 +1162,7 @@ impl ModulesManager {
         // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub async fn set_instance_enabled(&self, in_module: ModType) -> (StatusType,ChangeResult) {
+    pub async fn set_instance_enabled(&self, in_module: BotModule) -> (StatusType,ChangeResult) {
         // at Instance level
         //  - If core module, do nothing
 
@@ -1194,7 +1197,7 @@ impl ModulesManager {
         // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub async fn set_ch_disabled(&self, in_module: ModType , in_chnl: ChType) -> (StatusType,ChangeResult) {
+    pub async fn set_ch_disabled(&self, in_module: BotModule , in_chnl: Channel) -> (StatusType,ChangeResult) {
         // at Instance level
         //  - If core module, do nothing
 
@@ -1232,7 +1235,7 @@ impl ModulesManager {
         // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
-    pub async fn set_ch_enabled(&self, in_module: ModType , in_chnl: ChType) -> (StatusType,ChangeResult) {
+    pub async fn set_ch_enabled(&self, in_module: BotModule , in_chnl: Channel) -> (StatusType,ChangeResult) {
         // at Instance level
         //  - If core module, do nothing
 
@@ -1272,16 +1275,16 @@ impl ModulesManager {
 
 
 
-    pub async fn add_botaction(&self, in_module: ModType, in_action: BotAction) {
+    pub async fn add_botaction(&self, in_module: BotModule, in_action: BotAction) {
         self.int_add_botaction(in_module,ModGroup::Custom,in_action).await;
     }
 
-    pub async fn add_core_act(&self, in_module: ModType, in_action: BotAction) {
+    pub async fn add_core_act(&self, in_module: BotModule, in_action: BotAction) {
         self.int_add_botaction(in_module,ModGroup::Core,in_action).await;
     }
 
 
-    pub async fn affirm_in_statusdb(&self,in_module:ModType,in_modgroup: ModGroup) {
+    pub async fn affirm_in_statusdb(&self,in_module:BotModule,in_modgroup: ModGroup) {
 
         let mut dbt = self.statusdb.write().await;
          
@@ -1297,7 +1300,7 @@ impl ModulesManager {
 
     }
 
-    async fn int_add_botaction(&self, in_module: ModType, in_modgroup: ModGroup, in_action: BotAction) {
+    async fn int_add_botaction(&self, in_module: BotModule, in_modgroup: ModGroup, in_action: BotAction) {
         botlog::trace(
             "Add botaction called",
             Some("ModulesManager > init()".to_string()),
@@ -1320,7 +1323,7 @@ impl ModulesManager {
         //    - If BotAction to Add is a BotCommand , In Module Manager DB (botactions),
         //       Check All Other BotAction Command Names & Aliases to ensure they don't conflict
 
-        async fn find_conflict_module(mgr: &ModulesManager, act: &BotAction) -> Option<ModType> {
+        async fn find_conflict_module(mgr: &ModulesManager, act: &BotAction) -> Option<BotModule> {
             if let BotAction::C(incmd) = act {
                 let actdb = mgr.botactions.read().await;
 
@@ -1395,12 +1398,12 @@ impl ModulesManager {
         );
     }
 
-    fn _statuscleanup(&self, _: Option<ChType>) {
+    fn _statuscleanup(&self, _: Option<Channel>) {
         // internal cleans up statusdb . For example :
         // - remove redudancies . If we see several Enabled("m"), only keep 1x
         // - Clarify Conflict. If we see Enabled("m") and Disabled("m") , we remove Enabled("m") and keep Disabled("m")
         // the IDEAL is that this is ran before every read/update operation to ensure quality
-        // Option<ChType> can pass Some(Channel("m")) (as an example) so statuscleanup only works on the given channel
+        // Option<Channel> can pass Some(Channel("m")) (as an example) so statuscleanup only works on the given channel
         // Passing None to chnl may be a heavy operation, as this will review and look at the whole table
     }
 }
@@ -1467,10 +1470,10 @@ mod core_modulesmanager {
      */
 
     async fn complex_workflow(
-        in_module: ModType , 
+        in_module: BotModule , 
         in_modgroup : ModGroup , 
-        in_chnl1 : ChType, 
-        in_chnl2 : ChType) 
+        in_chnl1 : Channel, 
+        in_chnl2 : Channel) 
     {
 
         
@@ -1643,7 +1646,7 @@ mod core_modulesmanager {
         let in_module = BotModule("Experiments01".to_string());
         let in_modgroup = ModGroup::Custom;
         let (in_chnl1,in_chnl2) = 
-            (ChType::Channel("TestChannel01".to_string()),ChType::Channel("TestChannel02".to_string()));
+            (Channel("TestChannel01".to_string()),Channel("TestChannel02".to_string()));
 
         complex_workflow(in_module, in_modgroup, in_chnl1, in_chnl2).await;
 
@@ -1659,7 +1662,7 @@ mod core_modulesmanager {
         let in_module = BotModule("CoreModule01".to_string());
         let in_modgroup = ModGroup::Core;
         let (in_chnl1,in_chnl2) = 
-            (ChType::Channel("TestChannel01".to_string()),ChType::Channel("TestChannel02".to_string()));
+            (Channel("TestChannel01".to_string()),Channel("TestChannel02".to_string()));
 
         complex_workflow(in_module, in_modgroup, in_chnl1, in_chnl2).await;
 
@@ -1701,7 +1704,7 @@ mod core_modulesmanager {
 
      async fn inner_enable_disable_complex(
         requestor:String,
-        channel:ChType,
+        channel:Channel,
         idmgr:IdentityManager,
         modsmgr:Arc<ModulesManager>) 
     {
@@ -1724,7 +1727,7 @@ mod core_modulesmanager {
 
         let requestor_badge = None; // If they are a Mod on the Given Channel already, that can be evaluated without the current badge
 
-        const OF_CMD_CHANNEL:ChType = Channel(String::new());
+        const OF_CMD_CHANNEL:Channel = Channel(String::new());
         
         let (admin_level_access,_) = idlock.can_user_run(requestor.clone(), channel.clone(), requestor_badge.clone(), 
         vec![
@@ -1773,7 +1776,7 @@ mod core_modulesmanager {
 
         // [-] requestor_badge: Option<ChatBadge>,
 
-        // [x] trg_module: ModType,
+        // [x] trg_module: BotModule,
         let trg_module = in_module;
 
         // [x] trg_level: StatusLvl,
@@ -2020,7 +2023,7 @@ mod core_modulesmanager {
 
         assert!(rslt.contains(&identity::UserRole::BotAdmin));
 
-        let channel = ChType::Channel("somechannel".to_string());
+        let channel = Channel("somechannel".to_string());
 
 
         inner_enable_disable_complex(requestor, channel, idmgr, modsmgr).await;
@@ -2058,7 +2061,7 @@ mod core_modulesmanager {
 
          let requestor = "mod_user".to_string();
          // let botadmin_badge = &None;
-         let channel = ChType::Channel("somechannel".to_string());
+         let channel = Channel("somechannel".to_string());
  
  
          idmgr.affirm_chatter_in_db(requestor.clone()).await;
@@ -2109,7 +2112,7 @@ mod core_modulesmanager {
 
 
          let requestor = "regular_user".to_string();
-         let channel = ChType::Channel("somechannel".to_string());
+         let channel = Channel("somechannel".to_string());
  
  
          idmgr.affirm_chatter_in_db(requestor.clone()).await;
@@ -2142,7 +2145,7 @@ mod core_modulesmanager {
 
          let requestor = "regular_user".to_string();
          
-         let channel = ChType::Channel("somechannel".to_string());
+         let channel = Channel("somechannel".to_string());
  
  
          idmgr.affirm_chatter_in_db(requestor.clone()).await;
diff --git a/src/core/chat.rs b/src/core/chat.rs
index fe49896..717b485 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -15,21 +15,21 @@ use rand::Rng;
 use crate::core::ratelimiter;
 use crate::core::ratelimiter::RateLimiter;
 
-use crate::core::botinstance::ChType;
+use crate::core::botinstance::Channel;
 use crate::core::botlog;
-pub use ChType::Channel;
+
 
 use tokio::time::{sleep, Duration};
 
 #[derive(Clone)]
 pub struct Chat {
-    pub ratelimiters: Arc<Mutex<HashMap<ChType, RateLimiter>>>, // used to limit messages sent per channel
+    pub ratelimiters: Arc<Mutex<HashMap<Channel, RateLimiter>>>, // used to limit messages sent per channel
     pub client: TwitchIRCClient<TCPTransport<TLS>, StaticLoginCredentials>,
 }
 
 impl Chat {
     pub fn init(
-        ratelimiters: HashMap<ChType, RateLimiter>,
+        ratelimiters: HashMap<Channel, RateLimiter>,
         client: TwitchIRCClient<TCPTransport<TLS>, StaticLoginCredentials>,
     ) -> Chat {
         Chat {
@@ -38,7 +38,7 @@ impl Chat {
         }
     }
 
-    pub async fn init_channel(&mut self, chnl: ChType) {
+    pub async fn init_channel(&mut self, chnl: Channel) {
         let n = RateLimiter::new();
         self.ratelimiters.lock().await.insert(chnl, n);
     }
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 0a27b60..20edc3e 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -8,7 +8,7 @@ use twitch_irc::message::PrivmsgMessage;
 use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util::{self, BotAR};
-use crate::core::botinstance::{ChType,ChangeResult};
+use crate::core::botinstance::{Channel,ChangeResult};
 use crate::core::botlog;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
@@ -60,8 +60,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         exec_body: actions_util::asyncbox(cmd_promote),
         help: String::from("promote"),
         required_roles: vec![
-            UserRole::Mod(ChType::Channel(String::new())),
-            UserRole::SupMod(ChType::Channel(String::new())),
+            UserRole::Mod(Channel(String::new())),
+            UserRole::SupMod(Channel(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -172,7 +172,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         sendername.clone(),
                         &sender_badge,
                         targetusr.to_string(),
-                        Some(ChType::Channel(targetchnl.clone())),
+                        Some(Channel(targetchnl.clone())),
                         target_bot_admin_role,
                     )
                     .await
@@ -232,8 +232,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         exec_body: actions_util::asyncbox(cmd_demote),
         help: String::from("demote"),
         required_roles: vec![
-            UserRole::Mod(ChType::Channel(String::new())),
-            UserRole::SupMod(ChType::Channel(String::new())),
+            UserRole::Mod(Channel(String::new())),
+            UserRole::SupMod(Channel(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -368,7 +368,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         sendername.clone(),
                         &sender_badge,
                         targetusr.to_string(),
-                        Some(ChType::Channel(targetchnl.clone())),
+                        Some(Channel(targetchnl.clone())),
                     )
                     .await
             }
@@ -424,8 +424,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         exec_body: actions_util::asyncbox(getroles),
         help: String::from("getroles"),
         required_roles: vec![
-            UserRole::Mod(ChType::Channel(String::new())),
-            UserRole::SupMod(ChType::Channel(String::new())),
+            UserRole::Mod(Channel(String::new())),
+            UserRole::SupMod(Channel(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -477,7 +477,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 idlock
                     .getspecialuserroles(
                         String::from(targetuser),
-                        Some(ChType::Channel(msg.channel_login.to_lowercase())),
+                        Some(Channel(msg.channel_login.to_lowercase())),
                     )
                     .await
             }
@@ -486,20 +486,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 let callersproles = idlock
                     .getspecialuserroles(
                         msg.sender.name.to_lowercase(),
-                        Some(ChType::Channel(targetchnl.to_lowercase().to_string())),
+                        Some(Channel(targetchnl.to_lowercase().to_string())),
                     )
                     .await;
 
-                if callersproles.contains(&UserRole::Mod(ChType::Channel(
+                if callersproles.contains(&UserRole::Mod(Channel(
                     targetchnl.to_lowercase().to_string(),
-                ))) || callersproles.contains(&UserRole::SupMod(ChType::Channel(
+                ))) || callersproles.contains(&UserRole::SupMod(Channel(
                     targetchnl.to_lowercase().to_string(),
                 ))) || callersproles.contains(&UserRole::Broadcaster)
                 {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(ChType::Channel(targetchnl.to_lowercase())),
+                            Some(Channel(targetchnl.to_lowercase())),
                         )
                         .await
                 } else {
@@ -507,7 +507,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(ChType::Channel(msg.channel_login.to_lowercase())),
+                            Some(Channel(msg.channel_login.to_lowercase())),
                         )
                         .await
                 }
@@ -535,18 +535,18 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string();
 
-            if sproles.contains(&UserRole::Mod(ChType::Channel(
+            if sproles.contains(&UserRole::Mod(Channel(
                 msg.channel_login.to_lowercase(),
-            ))) || sproles.contains(&UserRole::SupMod(ChType::Channel(
+            ))) || sproles.contains(&UserRole::SupMod(Channel(
                 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(ChType::Channel(
+        } else if sproles.contains(&UserRole::Mod(Channel(
             msg.channel_login.to_lowercase(),
-        ))) || sproles.contains(&UserRole::SupMod(ChType::Channel(
+        ))) || sproles.contains(&UserRole::SupMod(Channel(
             msg.channel_login.to_lowercase(),
         ))) || sproles.contains(&UserRole::BotAdmin)
         {
@@ -578,8 +578,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum UserRole {
     Chatter,
-    Mod(ChType),    // String specifies Channel
-    SupMod(ChType), // String specifies Channel
+    Mod(Channel),    // String specifies Channel
+    SupMod(Channel), // String specifies Channel
     Broadcaster,
     BotAdmin,
 }
@@ -698,7 +698,7 @@ impl IdentityManager {
 
         self.can_user_run(
             msg.sender.name.to_owned(),
-            ChType::Channel(msg.channel_login.to_owned()),
+            Channel(msg.channel_login.to_owned()),
             sender_badge,
             cmdreqroles,
         )
@@ -709,7 +709,7 @@ impl IdentityManager {
     pub async fn can_user_run(
         &mut self,
         usr: String,
-        channelname: ChType,
+        channelname: Channel,
         chat_badge: Option<ChatBadge>,
         cmdreqroles: Vec<UserRole>, // ) -> Result<Permissible,Box<dyn Error>> {
     ) -> (Permissible, ChangeResult) {
@@ -799,8 +799,8 @@ impl IdentityManager {
             // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("")  , Ok(Permissible::Allow)
             Some(ChatBadge::Broadcaster) => {
                 if cmdreqroles.contains(&UserRole::Broadcaster)
-                    || cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new())))
-                    || cmdreqroles.contains(&UserRole::SupMod(ChType::Channel(String::new())))
+                    || cmdreqroles.contains(&UserRole::Mod(Channel(String::new())))
+                    || cmdreqroles.contains(&UserRole::SupMod(Channel(String::new())))
                 {
                     // return Ok(Permissible::Allow)
                     return (
@@ -869,7 +869,7 @@ impl IdentityManager {
             None,
         );
 
-        if cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) {
+        if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) {
             botlog::trace(
                 "Command requires Mod Role",
                 Some("identity.rs > can_user_run()".to_string()),
@@ -905,7 +905,7 @@ impl IdentityManager {
 
         // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
 
-        if cmdreqroles.contains(&UserRole::SupMod(ChType::Channel(String::new()))) {
+        if cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) {
             if let Some(a) = self
                 .special_roles_users
                 .read()
@@ -979,7 +979,7 @@ impl IdentityManager {
         authorizer: String,
         authorizer_badge: &Option<ChatBadge>,
         trgchatter: String,
-        channel: Option<ChType>,
+        channel: Option<Channel>,
         trg_role: Option<UserRole>,
     ) -> ChangeResult {
         botlog::trace(
@@ -1163,7 +1163,7 @@ impl IdentityManager {
         authorizer: String,
         authorizer_badge: &Option<ChatBadge>,
         trgchatter: String,
-        channel: Option<ChType>,
+        channel: Option<Channel>,
     ) -> ChangeResult {
         botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?}",
                     authorizer,trgchatter,channel), Some("identity.rs > demote()".to_string()), None);
@@ -1260,7 +1260,7 @@ impl IdentityManager {
     pub async fn getspecialuserroles(
         &self,
         chattername: String,
-        channel: Option<ChType>,
+        channel: Option<Channel>,
     ) -> Vec<UserRole> {
         /*
            Note : Ideally this be called for a given chatter name ?
@@ -1285,14 +1285,14 @@ impl IdentityManager {
         let channel_out = match channel {
             Some(channel_tmp) => {
                 match channel_tmp {
-                    ChType::Channel(channel_tmp) => {
+                    Channel(channel_tmp) => {
                         // In this block, Some input channel is given
                         // We're comparing the channel name with chattername to determine if they're a broadcaster
                         if chattername == channel_tmp.to_lowercase() {
                             evalsproles.push(UserRole::Broadcaster);
                         }
 
-                        Some(ChType::Channel(channel_tmp))
+                        Some(Channel(channel_tmp))
                     } // _ => ()
                 }
             }
@@ -1379,8 +1379,8 @@ mod core_identity {
     fn user_role_identity() {
         Log::set_file_ext(Extension::Log);
         assert_eq!(
-            UserRole::SupMod(ChType::Channel("strong".to_string())),
-            UserRole::SupMod(ChType::Channel("Strong".to_lowercase()))
+            UserRole::SupMod(Channel("strong".to_string())),
+            UserRole::SupMod(Channel("Strong".to_lowercase()))
         );
     }
 
@@ -1395,7 +1395,7 @@ mod core_identity {
 
             let (usr, channelname, chat_badge, cmdreqroles) = (
                 bot,
-                ChType::Channel("twitchchanneltest".to_string()),
+                Channel("twitchchanneltest".to_string()),
                 None,
                 vec![]
             );
@@ -1420,7 +1420,7 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Mod Attempts to Promote User
-        let channel = Some(ChType::Channel("twitchchanneltest".to_string()));
+        let channel = Some(Channel("twitchchanneltest".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Mod);
         let authorizer = "chatMod".to_string();
@@ -1450,7 +1450,7 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Broadcaster Promotes Chatter to SupMod
-        let channel = Some(ChType::Channel("broadcasterer".to_string()));
+        let channel = Some(Channel("broadcasterer".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
         let authorizer = "broadcasterer".to_string();
@@ -1475,7 +1475,7 @@ mod core_identity {
             .getspecialuserroles(trgchatter.clone(), channel.clone())
             .await;
 
-        assert!(rslt.contains(&UserRole::Mod(ChType::Channel("broadcasterer".to_string()))));
+        assert!(rslt.contains(&UserRole::Mod(Channel("broadcasterer".to_string()))));
 
         let rslt = test_id_mgr
             .promote(
@@ -1496,7 +1496,7 @@ mod core_identity {
             .getspecialuserroles(trgchatter.clone(), channel.clone())
             .await;
 
-        assert!(rslt.contains(&UserRole::SupMod(ChType::Channel(
+        assert!(rslt.contains(&UserRole::SupMod(Channel(
             "broadcasterer".to_string()
         ))));
 
@@ -1530,7 +1530,7 @@ mod core_identity {
         let broadcaster = "broadcasterer".to_string();
         let broadcaster_badge = &Some(ChatBadge::Broadcaster);
         // let channel = Some(ChType::Channel(broadcaster.clone()));
-        let channel = ChType::Channel(broadcaster.clone());
+        let channel = Channel(broadcaster.clone());
         let supchatter = "superModerator".to_string();
         let trg_role = None;
 
@@ -1575,7 +1575,7 @@ mod core_identity {
         // let broadcaster = "broadcasterer".to_string();
         let authorizer = supchatter;
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
-        let channel = Some(ChType::Channel(broadcaster.clone()));
+        let channel = Some(Channel(broadcaster.clone()));
         let trgchatter = "regularChatter".to_string();
         let trg_role = None;
 
@@ -1646,7 +1646,7 @@ mod core_identity {
         // let broadcaster = "broadcasterer".to_string();
         let authorizer = botadmin;
         let authorizer_badge = botadmin_badge;
-        let channel = Some(ChType::Channel("somechannel".to_string()));
+        let channel = Some(Channel("somechannel".to_string()));
         let trgchatter = "regularChatter".to_string();
         let trg_role = None;
 
@@ -1721,7 +1721,7 @@ mod core_identity {
 
         let supmod = "supmoder".to_string();
 
-        let channel = Some(ChType::Channel("somechannel".to_string()));
+        let channel = Some(Channel("somechannel".to_string()));
 
         test_id_mgr.affirm_chatter_in_db(supmod.clone()).await;
         test_id_mgr
diff --git a/src/custom/experiments.rs b/src/custom/experiments.rs
index 529e551..f83693a 100644
--- a/src/custom/experiments.rs
+++ b/src/custom/experiments.rs
@@ -16,8 +16,7 @@ use std::sync::Arc;
 use twitch_irc::message::PrivmsgMessage;
 
 // use crate::core::botinstance::ChType::Channel;
-use crate::core::botinstance::ChType;
-use ChType::Channel;
+use crate::core::botinstance::Channel;
 use crate::core::botlog;
 
 use crate::core::bot_actions::actions_util::{self, BotAR};
@@ -29,7 +28,7 @@ use tokio::time::{sleep, Duration};
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:ChType = Channel(String::new());
+    const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
     // 1. Define the BotAction
     let botc1 = BotCommand {

From bed61c2830cf1b9dbe9477fda2e5245b228cc7b3 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Sat, 23 Mar 2024 14:33:45 -0300
Subject: [PATCH 30/98] pub struct changes

look into error at identity:1333
---
 .cargo/config.toml        |  2 +-
 src/core/botinstance.rs   | 10 ++++--
 src/core/botmodules.rs    |  9 ++++-
 src/core/chat.rs          |  2 +-
 src/core/identity.rs      | 76 +++++++++++++++++++--------------------
 src/custom/experiments.rs | 10 +++---
 6 files changed, 61 insertions(+), 48 deletions(-)

diff --git a/.cargo/config.toml b/.cargo/config.toml
index 2bcdad5..46ba45d 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -1,4 +1,4 @@
 
 [env]
 # Based on https://doc.rust-lang.org/cargo/reference/config.html
-OtherBots = "Supibot,buttsbot,PotatBotat,StreamElements"
+OtherBots = "Supibot,buttsbot,PotatBotat,StreamElements,yuumeibot"
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index a668dac..1522c30 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -43,8 +43,14 @@ pub enum ChangeResult {
 // pub use ChType::Channel;
 //
 //simplifying from enum to struct
-pub struct Channel(pub String);
-
+pub struct Channel(String);
+impl Channel
+{
+    pub fn construct(channel_string:String) -> Channel
+    {
+        Channel(channel_string)
+    }
+}
 use super::botmodules::StatusType;
 
 #[derive(Clone)]
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 9c7152f..42943b6 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -415,8 +415,15 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 //     BotModule(String),
 // }
 
-pub struct BotModule(pub String);
+pub struct BotModule(String);
 //botmodule simplified from enum to tuple struct
+impl BotModule{
+    pub fn construct(module_name:String) -> BotModule
+    {
+        BotModule(module_name)
+    }
+}
+
 
 impl PartialEq for BotModule {
     fn eq(&self, other: &Self) -> bool {
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 717b485..78873b9 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -58,7 +58,7 @@ impl Chat {
 
         let contextratelimiter = rllock
             // .get_mut()
-            .get_mut(&Channel(String::from(&msg.channel_login)))
+            .get_mut(&Channel::construct(String::from(&msg.channel_login)))
             .expect("ERROR: Issue with Rate limiters");
 
         // Continue to check the limiter and sleep if required if the minimum is not reached
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 20edc3e..eb70d3c 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -54,14 +54,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     );
 
     let tempb = BotCommand {
-        module: BotModule(String::from("identity")),
+        module: BotModule::construct(String::from("identity")),
         command: String::from("promote"), // command call name
         alias: vec![],                    // String of alternative names
         exec_body: actions_util::asyncbox(cmd_promote),
         help: String::from("promote"),
         required_roles: vec![
-            UserRole::Mod(Channel(String::new())),
-            UserRole::SupMod(Channel(String::new())),
+            UserRole::Mod(Channel::construct(String::new())),
+            UserRole::SupMod(Channel::construct(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -172,7 +172,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         sendername.clone(),
                         &sender_badge,
                         targetusr.to_string(),
-                        Some(Channel(targetchnl.clone())),
+                        Some(Channel::construct(targetchnl.clone())),
                         target_bot_admin_role,
                     )
                     .await
@@ -226,14 +226,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     }
 
     let tempb = BotCommand {
-        module: BotModule(String::from("identity")),
+        module: BotModule::construct(String::from("identity")),
         command: String::from("demote"), // command call name
         alias: vec![],                   // String of alternative names
         exec_body: actions_util::asyncbox(cmd_demote),
         help: String::from("demote"),
         required_roles: vec![
-            UserRole::Mod(Channel(String::new())),
-            UserRole::SupMod(Channel(String::new())),
+            UserRole::Mod(Channel::construct(String::new())),
+            UserRole::SupMod(Channel::construct(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -368,7 +368,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         sendername.clone(),
                         &sender_badge,
                         targetusr.to_string(),
-                        Some(Channel(targetchnl.clone())),
+                        Some(Channel::construct(targetchnl.clone())),
                     )
                     .await
             }
@@ -418,14 +418,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     }
 
     let tempcomm = BotCommand {
-        module: BotModule(String::from("identity")),
+        module: BotModule::construct(String::from("identity")),
         command: String::from("getroles"), // command call name
         alias: vec![],                     // String of alternative names
         exec_body: actions_util::asyncbox(getroles),
         help: String::from("getroles"),
         required_roles: vec![
-            UserRole::Mod(Channel(String::new())),
-            UserRole::SupMod(Channel(String::new())),
+            UserRole::Mod(Channel::construct(String::new())),
+            UserRole::SupMod(Channel::construct(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -477,7 +477,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 idlock
                     .getspecialuserroles(
                         String::from(targetuser),
-                        Some(Channel(msg.channel_login.to_lowercase())),
+                        Some(Channel::construct(msg.channel_login.to_lowercase())),
                     )
                     .await
             }
@@ -486,20 +486,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 let callersproles = idlock
                     .getspecialuserroles(
                         msg.sender.name.to_lowercase(),
-                        Some(Channel(targetchnl.to_lowercase().to_string())),
+                        Some(Channel::construct(targetchnl.to_lowercase().to_string())),
                     )
                     .await;
 
-                if callersproles.contains(&UserRole::Mod(Channel(
+                if callersproles.contains(&UserRole::Mod(Channel::construct(
                     targetchnl.to_lowercase().to_string(),
-                ))) || callersproles.contains(&UserRole::SupMod(Channel(
+                ))) || callersproles.contains(&UserRole::SupMod(Channel::construct(
                     targetchnl.to_lowercase().to_string(),
                 ))) || callersproles.contains(&UserRole::Broadcaster)
                 {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(Channel(targetchnl.to_lowercase())),
+                            Some(Channel::construct(targetchnl.to_lowercase())),
                         )
                         .await
                 } else {
@@ -507,7 +507,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(Channel(msg.channel_login.to_lowercase())),
+                            Some(Channel::construct(msg.channel_login.to_lowercase())),
                         )
                         .await
                 }
@@ -535,18 +535,18 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string();
 
-            if sproles.contains(&UserRole::Mod(Channel(
+            if sproles.contains(&UserRole::Mod(Channel::construct(
                 msg.channel_login.to_lowercase(),
-            ))) || sproles.contains(&UserRole::SupMod(Channel(
+            ))) || sproles.contains(&UserRole::SupMod(Channel::construct(
                 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(
+        } else if sproles.contains(&UserRole::Mod(Channel::construct(
             msg.channel_login.to_lowercase(),
-        ))) || sproles.contains(&UserRole::SupMod(Channel(
+        ))) || sproles.contains(&UserRole::SupMod(Channel::construct(
             msg.channel_login.to_lowercase(),
         ))) || sproles.contains(&UserRole::BotAdmin)
         {
@@ -698,7 +698,7 @@ impl IdentityManager {
 
         self.can_user_run(
             msg.sender.name.to_owned(),
-            Channel(msg.channel_login.to_owned()),
+            Channel::construct(msg.channel_login.to_owned()),
             sender_badge,
             cmdreqroles,
         )
@@ -799,8 +799,8 @@ impl IdentityManager {
             // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("")  , Ok(Permissible::Allow)
             Some(ChatBadge::Broadcaster) => {
                 if cmdreqroles.contains(&UserRole::Broadcaster)
-                    || cmdreqroles.contains(&UserRole::Mod(Channel(String::new())))
-                    || cmdreqroles.contains(&UserRole::SupMod(Channel(String::new())))
+                    || cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new())))
+                    || cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new())))
                 {
                     // return Ok(Permissible::Allow)
                     return (
@@ -869,7 +869,7 @@ impl IdentityManager {
             None,
         );
 
-        if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) {
+        if cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) {
             botlog::trace(
                 "Command requires Mod Role",
                 Some("identity.rs > can_user_run()".to_string()),
@@ -905,7 +905,7 @@ impl IdentityManager {
 
         // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
 
-        if cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) {
+        if cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) {
             if let Some(a) = self
                 .special_roles_users
                 .read()
@@ -1292,7 +1292,7 @@ impl IdentityManager {
                             evalsproles.push(UserRole::Broadcaster);
                         }
 
-                        Some(Channel(channel_tmp))
+                        Some(Channel::construct(channel_tmp))
                     } // _ => ()
                 }
             }
@@ -1379,8 +1379,8 @@ mod core_identity {
     fn user_role_identity() {
         Log::set_file_ext(Extension::Log);
         assert_eq!(
-            UserRole::SupMod(Channel("strong".to_string())),
-            UserRole::SupMod(Channel("Strong".to_lowercase()))
+            UserRole::SupMod(Channel::construct("strong".to_string())),
+            UserRole::SupMod(Channel::construct("Strong".to_lowercase()))
         );
     }
 
@@ -1395,7 +1395,7 @@ mod core_identity {
 
             let (usr, channelname, chat_badge, cmdreqroles) = (
                 bot,
-                Channel("twitchchanneltest".to_string()),
+                Channel::construct("twitchchanneltest".to_string()),
                 None,
                 vec![]
             );
@@ -1420,7 +1420,7 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Mod Attempts to Promote User
-        let channel = Some(Channel("twitchchanneltest".to_string()));
+        let channel = Some(Channel::construct("twitchchanneltest".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Mod);
         let authorizer = "chatMod".to_string();
@@ -1450,7 +1450,7 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Broadcaster Promotes Chatter to SupMod
-        let channel = Some(Channel("broadcasterer".to_string()));
+        let channel = Some(Channel::construct("broadcasterer".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
         let authorizer = "broadcasterer".to_string();
@@ -1475,7 +1475,7 @@ mod core_identity {
             .getspecialuserroles(trgchatter.clone(), channel.clone())
             .await;
 
-        assert!(rslt.contains(&UserRole::Mod(Channel("broadcasterer".to_string()))));
+        assert!(rslt.contains(&UserRole::Mod(Channel::construct("broadcasterer".to_string()))));
 
         let rslt = test_id_mgr
             .promote(
@@ -1496,7 +1496,7 @@ mod core_identity {
             .getspecialuserroles(trgchatter.clone(), channel.clone())
             .await;
 
-        assert!(rslt.contains(&UserRole::SupMod(Channel(
+        assert!(rslt.contains(&UserRole::SupMod(Channel::construct(
             "broadcasterer".to_string()
         ))));
 
@@ -1530,7 +1530,7 @@ mod core_identity {
         let broadcaster = "broadcasterer".to_string();
         let broadcaster_badge = &Some(ChatBadge::Broadcaster);
         // let channel = Some(ChType::Channel(broadcaster.clone()));
-        let channel = Channel(broadcaster.clone());
+        let channel = Channel::construct(broadcaster.clone());
         let supchatter = "superModerator".to_string();
         let trg_role = None;
 
@@ -1575,7 +1575,7 @@ mod core_identity {
         // let broadcaster = "broadcasterer".to_string();
         let authorizer = supchatter;
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
-        let channel = Some(Channel(broadcaster.clone()));
+        let channel = Some(Channel::construct(broadcaster.clone()));
         let trgchatter = "regularChatter".to_string();
         let trg_role = None;
 
@@ -1646,7 +1646,7 @@ mod core_identity {
         // let broadcaster = "broadcasterer".to_string();
         let authorizer = botadmin;
         let authorizer_badge = botadmin_badge;
-        let channel = Some(Channel("somechannel".to_string()));
+        let channel = Some(Channel::construct("somechannel".to_string()));
         let trgchatter = "regularChatter".to_string();
         let trg_role = None;
 
@@ -1721,7 +1721,7 @@ mod core_identity {
 
         let supmod = "supmoder".to_string();
 
-        let channel = Some(Channel("somechannel".to_string()));
+        let channel = Some(Channel::construct("somechannel".to_string()));
 
         test_id_mgr.affirm_chatter_in_db(supmod.clone()).await;
         test_id_mgr
diff --git a/src/custom/experiments.rs b/src/custom/experiments.rs
index f83693a..01eb88f 100644
--- a/src/custom/experiments.rs
+++ b/src/custom/experiments.rs
@@ -28,11 +28,11 @@ use tokio::time::{sleep, Duration};
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:Channel = Channel(String::new());
+    const OF_CMD_CHANNEL:Channel = Channel::construct(String::new());
 
     // 1. Define the BotAction
     let botc1 = BotCommand {
-        module: BotModule(String::from("experiments001")),
+        module: BotModule::construct(String::from("experiments001")),
         command: String::from("test1"), // command call name
         alias: vec![
             String::from("tester1"), 
@@ -50,7 +50,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
     // 1. Define the BotAction
     let list1 = Listener {
-        module: BotModule(String::from("experiments001")),
+        module: BotModule::construct(String::from("experiments001")),
         name: String::from("GoodGirl Listener"),
         exec_body: actions_util::asyncbox(good_girl),
         help: String::from(""),
@@ -73,7 +73,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
     // 1. Define the BotAction
     let botc1 = BotCommand {
-        module: BotModule(String::from("experiments001")),
+        module: BotModule::construct(String::from("experiments001")),
         command: String::from("babygirl"), // command call name
         alias: vec![], // String of alternative names
         exec_body: actions_util::asyncbox(babygirl),
@@ -92,7 +92,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     
     // 1. Define the BotAction
     let botc1 = BotCommand {
-        module: BotModule(String::from("experiments001")),
+        module: BotModule::construct(String::from("experiments001")),
         command: String::from("rtest"), // command call name
         alias: vec![], // String of alternative names
         exec_body: actions_util::asyncbox(routinelike),

From 0f1cb576a41856f1d16c664cc8f5b2ae33279224 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 14:00:02 -0400
Subject: [PATCH 31/98] reworked broadcaster check in identity

---
 src/core/identity.rs | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index eb70d3c..4f683bd 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -1283,22 +1283,19 @@ impl IdentityManager {
 
         // Checks if broadcaster
         let channel_out = match channel {
-            Some(channel_tmp) => {
-                match channel_tmp {
-                    Channel(channel_tmp) => {
-                        // In this block, Some input channel is given
-                        // We're comparing the channel name with chattername to determine if they're a broadcaster
-                        if chattername == channel_tmp.to_lowercase() {
-                            evalsproles.push(UserRole::Broadcaster);
-                        }
-
-                        Some(Channel::construct(channel_tmp))
-                    } // _ => ()
+            Some(chnl) => {
+                // In this block, Some input channel is given
+                // We're comparing the channel name with chattername to determine if they're a broadcaster
+                if chattername == chnl.0 
+                {
+                    evalsproles.push(UserRole::Broadcaster);
                 }
-            }
+                Some(chnl)
+            },
             None => None,
         };
 
+
         let rolesdb = Arc::clone(&self.special_roles_users);
 
         let rolesdb_lock = rolesdb.read().await;

From 9a3d0aacda0b48bdb9f4d81239e99bb35c9e4bc3 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 14:00:20 -0400
Subject: [PATCH 32/98] adj off construct

adj off construct
---
 src/core/botmodules.rs    | 16 ++++----
 src/core/chat.rs          |  2 +-
 src/core/identity.rs      | 84 ++++++++++++++++++++++-----------------
 src/custom/experiments.rs | 10 ++---
 4 files changed, 61 insertions(+), 51 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 42943b6..f1c9a67 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -415,14 +415,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 //     BotModule(String),
 // }
 
-pub struct BotModule(String);
-//botmodule simplified from enum to tuple struct
-impl BotModule{
-    pub fn construct(module_name:String) -> BotModule
-    {
-        BotModule(module_name)
-    }
-}
+pub struct BotModule(pub String);
+// //botmodule simplified from enum to tuple struct
+// impl BotModule{
+//     pub fn construct(module_name:String) -> BotModule
+//     {
+//         BotModule(module_name)
+//     }
+// }
 
 
 impl PartialEq for BotModule {
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 78873b9..717b485 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -58,7 +58,7 @@ impl Chat {
 
         let contextratelimiter = rllock
             // .get_mut()
-            .get_mut(&Channel::construct(String::from(&msg.channel_login)))
+            .get_mut(&Channel(String::from(&msg.channel_login)))
             .expect("ERROR: Issue with Rate limiters");
 
         // Continue to check the limiter and sleep if required if the minimum is not reached
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 4f683bd..e816e9f 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -54,14 +54,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     );
 
     let tempb = BotCommand {
-        module: BotModule::construct(String::from("identity")),
+        module: BotModule(String::from("identity")),
         command: String::from("promote"), // command call name
         alias: vec![],                    // String of alternative names
         exec_body: actions_util::asyncbox(cmd_promote),
         help: String::from("promote"),
         required_roles: vec![
-            UserRole::Mod(Channel::construct(String::new())),
-            UserRole::SupMod(Channel::construct(String::new())),
+            UserRole::Mod(Channel(String::new())),
+            UserRole::SupMod(Channel(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -172,7 +172,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         sendername.clone(),
                         &sender_badge,
                         targetusr.to_string(),
-                        Some(Channel::construct(targetchnl.clone())),
+                        Some(Channel(targetchnl.clone())),
                         target_bot_admin_role,
                     )
                     .await
@@ -226,14 +226,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     }
 
     let tempb = BotCommand {
-        module: BotModule::construct(String::from("identity")),
+        module: BotModule(String::from("identity")),
         command: String::from("demote"), // command call name
         alias: vec![],                   // String of alternative names
         exec_body: actions_util::asyncbox(cmd_demote),
         help: String::from("demote"),
         required_roles: vec![
-            UserRole::Mod(Channel::construct(String::new())),
-            UserRole::SupMod(Channel::construct(String::new())),
+            UserRole::Mod(Channel(String::new())),
+            UserRole::SupMod(Channel(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -368,7 +368,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         sendername.clone(),
                         &sender_badge,
                         targetusr.to_string(),
-                        Some(Channel::construct(targetchnl.clone())),
+                        Some(Channel(targetchnl.clone())),
                     )
                     .await
             }
@@ -418,14 +418,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     }
 
     let tempcomm = BotCommand {
-        module: BotModule::construct(String::from("identity")),
+        module: BotModule(String::from("identity")),
         command: String::from("getroles"), // command call name
         alias: vec![],                     // String of alternative names
         exec_body: actions_util::asyncbox(getroles),
         help: String::from("getroles"),
         required_roles: vec![
-            UserRole::Mod(Channel::construct(String::new())),
-            UserRole::SupMod(Channel::construct(String::new())),
+            UserRole::Mod(Channel(String::new())),
+            UserRole::SupMod(Channel(String::new())),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -477,7 +477,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 idlock
                     .getspecialuserroles(
                         String::from(targetuser),
-                        Some(Channel::construct(msg.channel_login.to_lowercase())),
+                        Some(Channel(msg.channel_login.to_lowercase())),
                     )
                     .await
             }
@@ -486,20 +486,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 let callersproles = idlock
                     .getspecialuserroles(
                         msg.sender.name.to_lowercase(),
-                        Some(Channel::construct(targetchnl.to_lowercase().to_string())),
+                        Some(Channel(targetchnl.to_lowercase().to_string())),
                     )
                     .await;
 
-                if callersproles.contains(&UserRole::Mod(Channel::construct(
+                if callersproles.contains(&UserRole::Mod(Channel(
                     targetchnl.to_lowercase().to_string(),
-                ))) || callersproles.contains(&UserRole::SupMod(Channel::construct(
+                ))) || callersproles.contains(&UserRole::SupMod(Channel(
                     targetchnl.to_lowercase().to_string(),
                 ))) || callersproles.contains(&UserRole::Broadcaster)
                 {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(Channel::construct(targetchnl.to_lowercase())),
+                            Some(Channel(targetchnl.to_lowercase())),
                         )
                         .await
                 } else {
@@ -507,7 +507,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(Channel::construct(msg.channel_login.to_lowercase())),
+                            Some(Channel(msg.channel_login.to_lowercase())),
                         )
                         .await
                 }
@@ -535,18 +535,18 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string();
 
-            if sproles.contains(&UserRole::Mod(Channel::construct(
+            if sproles.contains(&UserRole::Mod(Channel(
                 msg.channel_login.to_lowercase(),
-            ))) || sproles.contains(&UserRole::SupMod(Channel::construct(
+            ))) || sproles.contains(&UserRole::SupMod(Channel(
                 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::construct(
+        } else if sproles.contains(&UserRole::Mod(Channel(
             msg.channel_login.to_lowercase(),
-        ))) || sproles.contains(&UserRole::SupMod(Channel::construct(
+        ))) || sproles.contains(&UserRole::SupMod(Channel(
             msg.channel_login.to_lowercase(),
         ))) || sproles.contains(&UserRole::BotAdmin)
         {
@@ -698,7 +698,8 @@ impl IdentityManager {
 
         self.can_user_run(
             msg.sender.name.to_owned(),
-            Channel::construct(msg.channel_login.to_owned()),
+            // Channel::construct(msg.channel_login.to_owned()),
+            Channel(msg.channel_login.to_owned()),
             sender_badge,
             cmdreqroles,
         )
@@ -798,9 +799,13 @@ impl IdentityManager {
             // [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow)
             // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("")  , Ok(Permissible::Allow)
             Some(ChatBadge::Broadcaster) => {
+                // if cmdreqroles.contains(&UserRole::Broadcaster)
+                //     || cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new())))
+                //     || cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new())))
+                // {
                 if cmdreqroles.contains(&UserRole::Broadcaster)
-                    || cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new())))
-                    || cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new())))
+                    || cmdreqroles.contains(&UserRole::Mod(Channel(String::new())))
+                    || cmdreqroles.contains(&UserRole::SupMod(Channel(String::new())))
                 {
                     // return Ok(Permissible::Allow)
                     return (
@@ -869,7 +874,8 @@ impl IdentityManager {
             None,
         );
 
-        if cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) {
+        // if cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) {
+        if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) {
             botlog::trace(
                 "Command requires Mod Role",
                 Some("identity.rs > can_user_run()".to_string()),
@@ -905,7 +911,8 @@ impl IdentityManager {
 
         // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
 
-        if cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) {
+        // if cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) {
+            if cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) {
             if let Some(a) = self
                 .special_roles_users
                 .read()
@@ -1376,8 +1383,8 @@ mod core_identity {
     fn user_role_identity() {
         Log::set_file_ext(Extension::Log);
         assert_eq!(
-            UserRole::SupMod(Channel::construct("strong".to_string())),
-            UserRole::SupMod(Channel::construct("Strong".to_lowercase()))
+            UserRole::SupMod(Channel("strong".to_string())),
+            UserRole::SupMod(Channel("Strong".to_lowercase()))
         );
     }
 
@@ -1392,7 +1399,8 @@ mod core_identity {
 
             let (usr, channelname, chat_badge, cmdreqroles) = (
                 bot,
-                Channel::construct("twitchchanneltest".to_string()),
+                // Channel::construct("twitchchanneltest".to_string()),
+                Channel("twitchchanneltest".to_string()),
                 None,
                 vec![]
             );
@@ -1417,7 +1425,8 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Mod Attempts to Promote User
-        let channel = Some(Channel::construct("twitchchanneltest".to_string()));
+        // let channel = Some(Channel::construct("twitchchanneltest".to_string()));
+        let channel = Some(Channel("twitchchanneltest".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Mod);
         let authorizer = "chatMod".to_string();
@@ -1447,7 +1456,8 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Broadcaster Promotes Chatter to SupMod
-        let channel = Some(Channel::construct("broadcasterer".to_string()));
+        // let channel = Some(Channel::construct("broadcasterer".to_string()));
+        let channel = Some(Channel("broadcasterer".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
         let authorizer = "broadcasterer".to_string();
@@ -1472,7 +1482,7 @@ mod core_identity {
             .getspecialuserroles(trgchatter.clone(), channel.clone())
             .await;
 
-        assert!(rslt.contains(&UserRole::Mod(Channel::construct("broadcasterer".to_string()))));
+        assert!(rslt.contains(&UserRole::Mod(Channel("broadcasterer".to_string()))));
 
         let rslt = test_id_mgr
             .promote(
@@ -1493,7 +1503,7 @@ mod core_identity {
             .getspecialuserroles(trgchatter.clone(), channel.clone())
             .await;
 
-        assert!(rslt.contains(&UserRole::SupMod(Channel::construct(
+        assert!(rslt.contains(&UserRole::SupMod(Channel(
             "broadcasterer".to_string()
         ))));
 
@@ -1527,7 +1537,7 @@ mod core_identity {
         let broadcaster = "broadcasterer".to_string();
         let broadcaster_badge = &Some(ChatBadge::Broadcaster);
         // let channel = Some(ChType::Channel(broadcaster.clone()));
-        let channel = Channel::construct(broadcaster.clone());
+        let channel = Channel(broadcaster.clone());
         let supchatter = "superModerator".to_string();
         let trg_role = None;
 
@@ -1572,7 +1582,7 @@ mod core_identity {
         // let broadcaster = "broadcasterer".to_string();
         let authorizer = supchatter;
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
-        let channel = Some(Channel::construct(broadcaster.clone()));
+        let channel = Some(Channel(broadcaster.clone()));
         let trgchatter = "regularChatter".to_string();
         let trg_role = None;
 
@@ -1643,7 +1653,7 @@ mod core_identity {
         // let broadcaster = "broadcasterer".to_string();
         let authorizer = botadmin;
         let authorizer_badge = botadmin_badge;
-        let channel = Some(Channel::construct("somechannel".to_string()));
+        let channel = Some(Channel("somechannel".to_string()));
         let trgchatter = "regularChatter".to_string();
         let trg_role = None;
 
@@ -1718,7 +1728,7 @@ mod core_identity {
 
         let supmod = "supmoder".to_string();
 
-        let channel = Some(Channel::construct("somechannel".to_string()));
+        let channel = Some(Channel("somechannel".to_string()));
 
         test_id_mgr.affirm_chatter_in_db(supmod.clone()).await;
         test_id_mgr
diff --git a/src/custom/experiments.rs b/src/custom/experiments.rs
index 01eb88f..f83693a 100644
--- a/src/custom/experiments.rs
+++ b/src/custom/experiments.rs
@@ -28,11 +28,11 @@ use tokio::time::{sleep, Duration};
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:Channel = Channel::construct(String::new());
+    const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
     // 1. Define the BotAction
     let botc1 = BotCommand {
-        module: BotModule::construct(String::from("experiments001")),
+        module: BotModule(String::from("experiments001")),
         command: String::from("test1"), // command call name
         alias: vec![
             String::from("tester1"), 
@@ -50,7 +50,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
     // 1. Define the BotAction
     let list1 = Listener {
-        module: BotModule::construct(String::from("experiments001")),
+        module: BotModule(String::from("experiments001")),
         name: String::from("GoodGirl Listener"),
         exec_body: actions_util::asyncbox(good_girl),
         help: String::from(""),
@@ -73,7 +73,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
     // 1. Define the BotAction
     let botc1 = BotCommand {
-        module: BotModule::construct(String::from("experiments001")),
+        module: BotModule(String::from("experiments001")),
         command: String::from("babygirl"), // command call name
         alias: vec![], // String of alternative names
         exec_body: actions_util::asyncbox(babygirl),
@@ -92,7 +92,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     
     // 1. Define the BotAction
     let botc1 = BotCommand {
-        module: BotModule::construct(String::from("experiments001")),
+        module: BotModule(String::from("experiments001")),
         command: String::from("rtest"), // command call name
         alias: vec![], // String of alternative names
         exec_body: actions_util::asyncbox(routinelike),

From 3a0e00c3239bb942183c068c2008016084c20598 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 14:52:41 -0400
Subject: [PATCH 33/98] comments cleanup

---
 src/core/botinstance.rs | 10 ++--------
 src/core/botmodules.rs  |  9 ---------
 2 files changed, 2 insertions(+), 17 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 1522c30..a668dac 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -43,14 +43,8 @@ pub enum ChangeResult {
 // pub use ChType::Channel;
 //
 //simplifying from enum to struct
-pub struct Channel(String);
-impl Channel
-{
-    pub fn construct(channel_string:String) -> Channel
-    {
-        Channel(channel_string)
-    }
-}
+pub struct Channel(pub String);
+
 use super::botmodules::StatusType;
 
 #[derive(Clone)]
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index f1c9a67..f9d7ff0 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -40,8 +40,6 @@ use crate::core::identity::{self, Permissible,IdentityManager};
 
 use crate::core::bot_actions;
 
-//pub use BotModule;
-
 use std::hash::{Hash, Hasher};
 
 use super::identity::ChatBadge;
@@ -416,13 +414,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 // }
 
 pub struct BotModule(pub String);
-// //botmodule simplified from enum to tuple struct
-// impl BotModule{
-//     pub fn construct(module_name:String) -> BotModule
-//     {
-//         BotModule(module_name)
-//     }
-// }
 
 
 impl PartialEq for BotModule {

From 4613d69e3f8095ecdb8cdcc26a2dfed3b4e1969f Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 16:58:46 -0400
Subject: [PATCH 34/98] smol

---
 src/custom/experimental/experiment002.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index d3b70e5..5f4226b 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -16,8 +16,8 @@ use std::sync::Arc;
 use twitch_irc::message::PrivmsgMessage;
 
 // use crate::core::botinstance::ChType::Channel;
-use crate::core::botinstance::ChType;
-use ChType::Channel;
+use crate::core::botinstance::Channel;
+// use ChType::Channel;
 use crate::core::botlog;
 
 use casual_logger::Log;
@@ -31,7 +31,7 @@ use crate::core::identity::UserRole::*;
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:ChType = Channel(String::new());
+    const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
 
     // 1. Define the BotAction

From ff6046bb1f7f0ae11c072fe389ff5b5a3d5dc37b Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 18:04:57 -0400
Subject: [PATCH 35/98] botcommands recognized in replies

---
 src/core/botinstance.rs | 95 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 90 insertions(+), 5 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index a668dac..8d76956 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -171,6 +171,7 @@ impl BotInstance {
                         );
                     }
                     ServerMessage::Privmsg(msg) => {
+                        
                         botlog::debug(
                             format!(
                                 "[Twitch Chat > {}] > {}: {}",
@@ -181,6 +182,17 @@ impl BotInstance {
                             Some(&msg),
                         );
 
+                        
+                        botlog::trace(
+                            format!(
+                                "[TRACE][Twitch Chat > {}] > {}: {:?}",
+                                msg.channel_login, msg.sender.name, msg
+                            )
+                            .as_str(),
+                            Some("BotInstance > runner()".to_string()),
+                            Some(&msg),
+                        );
+
                         BotInstance::listener_main_prvmsg(Arc::clone(&bot), &msg).await;
                     }
                     ServerMessage::Whisper(msg) => {
@@ -243,6 +255,59 @@ impl BotInstance {
             Some(msg),
         );
 
+                                
+        // /*
+        //     [ ] Here, msg is taken, and message_text is split so we can pull the first argument
+        // */
+
+        // let inpt = msg
+        //     .message_text
+        //     .split(' ')
+        //     .next()
+        //     .expect("ERROR during BotCommand");
+
+        /*
+            [ ] What we should do instead is : 
+            1. Check if the message is related to a Reply (so we know how many arguments we should skip)
+            2. If a reply, skip the first argument
+        */
+
+        let mut msgiter= msg
+            .message_text
+            .split(' ');
+
+        let arg1 = msgiter.next();
+        let arg2 = msgiter.next();
+
+        let reply = if let Some(replyidout) = msg.source.tags.0.get("reply-thread-parent-msg-id") {
+                if let Some(replyid) = replyidout {
+                    // println!("Detected Reply : {}",replyid);
+                    Some(replyid)
+                } else { None }
+            } else { None }
+        ;
+
+        // let inpt = match reply {
+        //     None => arg1, // Regular message, use the first arg as the command
+        //     Some(_) => arg2, // A reply message, use the 2nd arg as the command
+        // };
+
+        
+        let inpt = match reply {
+            None => {  // Regular message, use the first arg as the command
+                match arg1 {
+                    None => return, // return if no argument found
+                    Some(a) => a,
+                }
+            },
+            Some(_) => {
+                match arg2 { // A reply message, use the 2nd arg as the command
+                    None => return, // return if no argument found
+                    Some(a) => a,
+                }
+            }, 
+        };
+
         for acts in (*actsdblock).values() {
             for a in acts {
                 match a {
@@ -263,11 +328,31 @@ impl BotInstance {
                             Some(msg),
                         );
 
-                        let inpt = msg
-                            .message_text
-                            .split(' ')
-                            .next()
-                            .expect("ERROR during BotCommand");
+                        
+                        // /*
+                        //     [ ] Here, msg is taken, and message_text is split so we can pull the first argument
+                        // */
+
+                        // let inpt = msg
+                        //     .message_text
+                        //     .split(' ')
+                        //     .next()
+                        //     .expect("ERROR during BotCommand");
+
+                        // /*
+                        //     [ ] What we should do instead is : 
+                        //     1. Check if the message is related to a Reply (so we know how many arguments we should skip)
+                        //     2. If a reply, skip the first argument
+                        //  */
+
+                        // if let Some(rslt) = msg.source.tags.0.get("reply-thread-parent-msg-id") {
+                        //     if let Some(rslt) = rslt {
+                        //         println!("Detected Reply : {}",rslt);
+                        //     }
+                        // }
+
+
+
 
                         // [x] Check if a bot command based on ...
                         //    [x] prefix + command

From 7e59b8b251b85c563bdff6e5fff205addcc2ca43 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 18:33:33 -0400
Subject: [PATCH 36/98] say chnl must be valid

---
 src/core/chat.rs                         | 11 +++++++++++
 src/custom/experimental/experiment002.rs | 22 ++++++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index e6b520d..6bd61e5 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -76,6 +76,17 @@ impl Chat {
             // },
         };
 
+        if self.client.get_channel_status(channel_login.clone()).await == (false,false) {
+            // in the case where the provided channel isn't something we're known to be connected to
+
+            botlog::warn(
+                &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
+                Some("Chat > send_botmsg".to_string()),
+                None,
+            );
+            return ;
+        }
+
         let rl = Arc::clone(&self.ratelimiters);
         let mut rllock = rl.lock().await;
 
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 5f4226b..5b4f11b 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -81,6 +81,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
     
 
+    
 
     match argrslt {
         Some((trgchnl,outmsg)) => {
@@ -93,6 +94,27 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
             let botlock = bot.read().await;
 
+            // [x] Validate first if trgchnl exists
+
+            if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
+                // in the case where the provided channel isn't something we're known to be connected to
+                // botlog::warn(
+                //     &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
+                //     Some("Chat > send_botmsg".to_string()),
+                //     None,
+                // );
+                // return ;
+
+                botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(&msg, format!("Cannot join channel : {}",trgchnl.to_string()))
+                .await;
+
+
+            }
+
+
             // uses chat.say_in_reply_to() for the bot controls for messages
             botlock
                 .botmgrs

From 0e12cd1bff68b06783bfd4bddbd5d65e1bece67c Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 19:20:43 -0400
Subject: [PATCH 37/98] experiments module

---
 src/custom/experimental/experiment002.rs | 98 +++++++++++++++++++-----
 1 file changed, 80 insertions(+), 18 deletions(-)

diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 5b4f11b..91043c8 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -65,31 +65,50 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
         <target channel> <message>
      */
 
+    
+     let reply_parent = if let Some(replyout) = msg.source.tags.0.get("reply-parent-msg-body") {
+        if let Some(replymsg) = replyout {
+            // println!("Detected Reply : {}",replyid);
+            Some(replymsg)
+        } else { None }
+    } else { None }
+    ;
+
+    let reply_parent_usr = if let Some(replyout) = msg.source.tags.0.get("reply-thread-parent-user-login") {
+        if let Some(replymsgusr) = replyout {
+            // println!("Detected Reply : {}",replyid);
+            Some(replymsgusr)
+        } else { None }
+    } else { None }
+    ;
+
     // [x] Unwraps arguments from message
 
     let argrslt = 
         if let Some((_,str1)) = msg.message_text.split_once(" ") {
-            if let Some((channelstr,msgstr)) = str1.split_once(" ") {
-                // println!("{}",cmdstr);
-                // println!("{}",channelstr);
-                // println!("{}",msgstr);
-                Some((channelstr,msgstr))
-            } 
-            else { None }
+            if reply_parent.is_none() {
+                if let Some((channelstr,msgstr)) = str1.split_once(" ") {
+                    Some((channelstr,msgstr))
+                } 
+                else { None }
+            } else {
+                if let Some((_,str2)) = str1.split_once(" ") {
+                    if let Some((channelstr,msgstr)) = str2.split_once(" ") {
+                    Some((channelstr,msgstr))
+                    } 
+                    else { None }
+                } 
+                else { None }
+            }
         }
         else { None };
 
-    
 
     
 
     match argrslt {
         Some((trgchnl,outmsg)) => {
 
-            let newoutmsg = format!("{} (from #{}) says : {}",
-                msg.sender.name,msg.channel_login, outmsg);
-
-
             let bot = Arc::clone(&bot);
 
             let botlock = bot.read().await;
@@ -98,23 +117,66 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
             if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
                 // in the case where the provided channel isn't something we're known to be connected to
-                // botlog::warn(
-                //     &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
-                //     Some("Chat > send_botmsg".to_string()),
-                //     None,
-                // );
+                botlog::warn(
+                    &format!("A message attempted to send for a Non-Joined Channel : {}",trgchnl.to_string().clone()),
+                    Some("Chat > send_botmsg".to_string()),
+                    None,
+                );
                 // return ;
 
                 botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, format!("Cannot join channel : {}",trgchnl.to_string()))
+                .say_in_reply_to(&msg, format!("Not a Joined Channel : {}",trgchnl.to_string()))
                 .await;
 
 
             }
 
 
+
+            // if let Some((arg1,arg1other)) = msg.message_text.split_once(' ') {
+
+            // }
+
+
+            /*
+                1. If a Reply , 
+                [ ] Get Parent Content message - reply_parent
+                [ ] Get Parent Chatter - reply_parent_usr 
+                [ ] Get Parent Channel - msg.channel_login
+                -> Share this first then
+                [ ] Get Reply Message (that triggered bot command) - msgstr
+                [ ] Get Reply Sender - msg.sender.name
+                [ ] Get Target Channel - trgchnl
+
+                2. If not a reply
+                [ ] Get Reply Message (that triggered bot command) - msgstr
+                [ ] Get Reply Sender - msg.sender.name
+                [ ] Get Target Channel - trgchnl
+             */
+
+            
+
+            if let Some(srcmsg) = reply_parent {
+
+                let newoutmsg = format!("{} from #{} Shared >> {} : {}",
+                    msg.sender.name,msg.channel_login, reply_parent_usr.unwrap(),srcmsg);
+
+                // uses chat.say_in_reply_to() for the bot controls for messages
+                botlock
+                .botmgrs
+                .chat
+                .say(trgchnl.to_string(), newoutmsg.to_string())
+                .await;
+            }
+
+            
+            let newoutmsg = format!("{} from #{} says : {}",
+                msg.sender.name,msg.channel_login, outmsg);
+
+
+
             // uses chat.say_in_reply_to() for the bot controls for messages
             botlock
                 .botmgrs

From 22b2ec746af6e0e4fee64a023a77d140d491a9d8 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 19:37:43 -0400
Subject: [PATCH 38/98] smol adj

---
 src/core/botinstance.rs                  | 12 ++++++
 src/custom/experimental/experiment002.rs | 54 ++++++++++++++++--------
 2 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 8d76956..c3d1d37 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -161,6 +161,18 @@ impl BotInstance {
 
             while let Some(message) = msglock.recv().await {
 
+                 
+                botlog::trace(
+                    format!(
+                        "[TRACE][ServerMessage] > {:?}",
+                       message
+                        )
+                    .as_str(),
+                    Some("BotInstance > runner()".to_string()),
+                    None,
+                );
+
+
                 match message {
                     ServerMessage::Notice(msg) => {
                         botlog::notice(
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 91043c8..67a9fa8 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -157,26 +157,16 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
              */
 
             
+            let newoutmsg = if let Some(srcmsg) = reply_parent {
 
-            if let Some(srcmsg) = reply_parent {
-
-                let newoutmsg = format!("{} from #{} Shared >> {} : {}",
-                    msg.sender.name,msg.channel_login, reply_parent_usr.unwrap(),srcmsg);
-
-                // uses chat.say_in_reply_to() for the bot controls for messages
-                botlock
-                .botmgrs
-                .chat
-                .say(trgchnl.to_string(), newoutmsg.to_string())
-                .await;
-            }
+                format!("{} from #{} says {} . Replying to: {} : {}",
+                    msg.sender.name,msg.channel_login,outmsg, reply_parent_usr.unwrap(),srcmsg)
+            } else {
+                format!("{} from #{} says : {}",
+                    msg.sender.name,msg.channel_login, outmsg)
+            };
 
             
-            let newoutmsg = format!("{} from #{} says : {}",
-                msg.sender.name,msg.channel_login, outmsg);
-
-
-
             // uses chat.say_in_reply_to() for the bot controls for messages
             botlock
                 .botmgrs
@@ -184,6 +174,36 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                 .say(trgchnl.to_string(), newoutmsg.to_string())
                 .await;
 
+
+
+            // if let Some(srcmsg) = reply_parent {
+
+            //     let newoutmsg = format!("{} from #{} Shared >> {} : {}",
+            //         msg.sender.name,msg.channel_login, reply_parent_usr.unwrap(),srcmsg);
+
+            //     // uses chat.say_in_reply_to() for the bot controls for messages
+            //     botlock
+            //     .botmgrs
+            //     .chat
+            //     .say(trgchnl.to_string(), newoutmsg.to_string())
+            //     .await;
+            // }
+
+            
+            // let newoutmsg = format!("{} from #{} says : {}",
+            //     msg.sender.name,msg.channel_login, outmsg);
+
+
+
+            // // uses chat.say_in_reply_to() for the bot controls for messages
+            // botlock
+            //     .botmgrs
+            //     .chat
+            //     .say(trgchnl.to_string(), newoutmsg.to_string())
+            //     .await;
+
+
+
             // botlog::debug(
             //         "Sayout had issues trying to parse arguments",
             //         Some("experiment002 > sayout".to_string()),

From 30a3e2af008e8cda4a0ab49d457e845fb8ff76eb Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 19:39:36 -0400
Subject: [PATCH 39/98] comments cleanup

---
 src/custom/experimental/experiment002.rs | 43 ------------------------
 1 file changed, 43 deletions(-)

diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 67a9fa8..fde184e 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -133,13 +133,6 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
             }
 
-
-
-            // if let Some((arg1,arg1other)) = msg.message_text.split_once(' ') {
-
-            // }
-
-
             /*
                 1. If a Reply , 
                 [ ] Get Parent Content message - reply_parent
@@ -166,7 +159,6 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                     msg.sender.name,msg.channel_login, outmsg)
             };
 
-            
             // uses chat.say_in_reply_to() for the bot controls for messages
             botlock
                 .botmgrs
@@ -176,41 +168,6 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
 
 
-            // if let Some(srcmsg) = reply_parent {
-
-            //     let newoutmsg = format!("{} from #{} Shared >> {} : {}",
-            //         msg.sender.name,msg.channel_login, reply_parent_usr.unwrap(),srcmsg);
-
-            //     // uses chat.say_in_reply_to() for the bot controls for messages
-            //     botlock
-            //     .botmgrs
-            //     .chat
-            //     .say(trgchnl.to_string(), newoutmsg.to_string())
-            //     .await;
-            // }
-
-            
-            // let newoutmsg = format!("{} from #{} says : {}",
-            //     msg.sender.name,msg.channel_login, outmsg);
-
-
-
-            // // uses chat.say_in_reply_to() for the bot controls for messages
-            // botlock
-            //     .botmgrs
-            //     .chat
-            //     .say(trgchnl.to_string(), newoutmsg.to_string())
-            //     .await;
-
-
-
-            // botlog::debug(
-            //         "Sayout had issues trying to parse arguments",
-            //         Some("experiment002 > sayout".to_string()),
-            //         Some(&msg),
-            //     );
-
-
         },
         None => {
             botlog::debug(

From 098f16ce870c824895ca06e881d03fd896995f42 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 20:06:45 -0400
Subject: [PATCH 40/98] say channel case insensitive

---
 src/core/botinstance.rs                  | 29 ++++--------------------
 src/core/chat.rs                         |  2 +-
 src/custom/experimental/experiment002.rs | 11 ++++++++-
 3 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index c3d1d37..e8b8793 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -181,6 +181,7 @@ impl BotInstance {
                             Some("BotInstance > runner()".to_string()),
                             None,
                         );
+                        Log::flush();
                     }
                     ServerMessage::Privmsg(msg) => {
                         
@@ -204,6 +205,7 @@ impl BotInstance {
                             Some("BotInstance > runner()".to_string()),
                             Some(&msg),
                         );
+                        Log::flush();
 
                         BotInstance::listener_main_prvmsg(Arc::clone(&bot), &msg).await;
                     }
@@ -213,6 +215,7 @@ impl BotInstance {
                             Some("BotInstance > runner()".to_string()),
                             None,
                         );
+                        Log::flush();
                     }
                     ServerMessage::Join(msg) => {
                         botlog::notice(
@@ -220,6 +223,7 @@ impl BotInstance {
                             Some("BotInstance > runner()".to_string()),
                             None,
                         );
+                        Log::flush();
                     }
                     ServerMessage::Part(msg) => {
                         botlog::notice(
@@ -227,6 +231,7 @@ impl BotInstance {
                             Some("BotInstance > runner()".to_string()),
                             None,
                         );
+                        Log::flush();
                     }
                     _ => {}
                 };
@@ -341,30 +346,6 @@ impl BotInstance {
                         );
 
                         
-                        // /*
-                        //     [ ] Here, msg is taken, and message_text is split so we can pull the first argument
-                        // */
-
-                        // let inpt = msg
-                        //     .message_text
-                        //     .split(' ')
-                        //     .next()
-                        //     .expect("ERROR during BotCommand");
-
-                        // /*
-                        //     [ ] What we should do instead is : 
-                        //     1. Check if the message is related to a Reply (so we know how many arguments we should skip)
-                        //     2. If a reply, skip the first argument
-                        //  */
-
-                        // if let Some(rslt) = msg.source.tags.0.get("reply-thread-parent-msg-id") {
-                        //     if let Some(rslt) = rslt {
-                        //         println!("Detected Reply : {}",rslt);
-                        //     }
-                        // }
-
-
-
 
                         // [x] Check if a bot command based on ...
                         //    [x] prefix + command
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 6bd61e5..8761516 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -174,7 +174,7 @@ impl Chat {
     pub async fn say(&self, channel_login: String, message: String) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
-        self.send_botmsg(BotMsgType::Say(channel_login, message)).await;
+        self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message)).await;
     }
 
     async fn _me(&self, _: String, _: String) {
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index fde184e..a00e76b 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -115,7 +115,16 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
             // [x] Validate first if trgchnl exists
 
-            if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
+            botlog::trace(
+                &format!("[TRACE] Evaluated status of {} : {:?}",
+                    trgchnl.to_string().clone(),botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await),
+                Some("Chat > send_botmsg".to_string()),
+                None,
+            );
+
+            // if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
+            if !botlock.bot_channels.contains(&Channel(trgchnl.to_lowercase().to_string().clone())) {
+
                 // in the case where the provided channel isn't something we're known to be connected to
                 botlog::warn(
                     &format!("A message attempted to send for a Non-Joined Channel : {}",trgchnl.to_string().clone()),

From d372d0dc791629f6bebaa7eb3862f48878f42b15 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 20:14:42 -0400
Subject: [PATCH 41/98] comments cleanup

---
 src/core/botinstance.rs | 5 -----
 src/core/chat.rs        | 6 ------
 2 files changed, 11 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index e8b8793..7c6f33b 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -304,11 +304,6 @@ impl BotInstance {
             } else { None }
         ;
 
-        // let inpt = match reply {
-        //     None => arg1, // Regular message, use the first arg as the command
-        //     Some(_) => arg2, // A reply message, use the 2nd arg as the command
-        // };
-
         
         let inpt = match reply {
             None => {  // Regular message, use the first arg as the command
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 8761516..370fcf5 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -71,9 +71,6 @@ impl Chat {
             BotMsgType::Say(a,b ) => {
                 (a.clone(),b.clone())
             },
-            // _ => {
-            //     panic!("ISSUE : NOT IMPLEMENTED")
-            // },
         };
 
         if self.client.get_channel_status(channel_login.clone()).await == (false,false) {
@@ -122,9 +119,6 @@ impl Chat {
                     BotMsgType::Say(a, _) => {
                         self.client.say(a, outmsg).await.unwrap();
                     }
-                    // _ => {
-                    //     panic!("ISSUE : NOT IMPLEMENTED")
-                    // },
                 }
                 
                 contextratelimiter.increment_counter();

From e4a44894d7a63de4ce099d81cf5de240158ece9e Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 20:29:18 -0400
Subject: [PATCH 42/98] clippy cleanup

clippy cleanup
---
 src/core/botinstance.rs                  | 23 ++++------------
 src/core/chat.rs                         |  4 +--
 src/custom/experimental.rs               |  2 +-
 src/custom/experimental/experiment002.rs | 34 +++++++++---------------
 4 files changed, 21 insertions(+), 42 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 7c6f33b..c5b6dca 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -272,17 +272,7 @@ impl BotInstance {
             Some(msg),
         );
 
-                                
-        // /*
-        //     [ ] Here, msg is taken, and message_text is split so we can pull the first argument
-        // */
-
-        // let inpt = msg
-        //     .message_text
-        //     .split(' ')
-        //     .next()
-        //     .expect("ERROR during BotCommand");
-
+                            
         /*
             [ ] What we should do instead is : 
             1. Check if the message is related to a Reply (so we know how many arguments we should skip)
@@ -295,14 +285,11 @@ impl BotInstance {
 
         let arg1 = msgiter.next();
         let arg2 = msgiter.next();
-
-        let reply = if let Some(replyidout) = msg.source.tags.0.get("reply-thread-parent-msg-id") {
-                if let Some(replyid) = replyidout {
-                    // println!("Detected Reply : {}",replyid);
-                    Some(replyid)
-                } else { None }
+        
+        let reply = if let Some(Some(replyid)) = msg.source.tags.0.get("reply-thread-parent-msg-id") {
+                Some(replyid)
             } else { None }
-        ;
+            ;
 
         
         let inpt = match reply {
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 370fcf5..1ba85e7 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -95,7 +95,7 @@ impl Chat {
 
         let contextratelimiter = rllock
             // .get_mut()
-            .get_mut(&Channel(String::from(channel_login.to_lowercase().clone())))
+            .get_mut(&Channel(channel_login.to_lowercase().clone()))
             .expect("ERROR: Issue with Rate limiters");
 
         // Continue to check the limiter and sleep if required if the minimum is not reached
@@ -132,7 +132,7 @@ impl Chat {
                     botlog::trace(
                         logstr.as_str(),
                         Some("Chat > send_botmsg".to_string()),
-                        Some(&msg),
+                        Some(msg),
                     );
                 } else {
                     botlog::trace(
diff --git a/src/custom/experimental.rs b/src/custom/experimental.rs
index e2aa67e..409abd1 100644
--- a/src/custom/experimental.rs
+++ b/src/custom/experimental.rs
@@ -5,7 +5,7 @@
 
 use std::sync::Arc;
 
-pub use crate::core::botinstance::BotInstance;
+// pub use crate::core::botinstance::BotInstance;
 pub use crate::core::botmodules::ModulesManager;
 
 // [ ] Load submodules
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index a00e76b..ff18642 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -65,41 +65,33 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
         <target channel> <message>
      */
 
-    
-     let reply_parent = if let Some(replyout) = msg.source.tags.0.get("reply-parent-msg-body") {
-        if let Some(replymsg) = replyout {
-            // println!("Detected Reply : {}",replyid);
-            Some(replymsg)
+    let reply_parent = if let Some(Some(reply)) = msg.source.tags.0.get("reply-parent-msg-body") {
+            Some(reply)
         } else { None }
-    } else { None }
     ;
 
-    let reply_parent_usr = if let Some(replyout) = msg.source.tags.0.get("reply-thread-parent-user-login") {
-        if let Some(replymsgusr) = replyout {
-            // println!("Detected Reply : {}",replyid);
-            Some(replymsgusr)
+
+    let reply_parent_usr = if let Some(Some(reply)) = msg.source.tags.0.get("reply-thread-parent-user-login") {
+        Some(reply)
         } else { None }
-    } else { None }
     ;
 
     // [x] Unwraps arguments from message
 
+
     let argrslt = 
-        if let Some((_,str1)) = msg.message_text.split_once(" ") {
+        if let Some((_,str1)) = msg.message_text.split_once(' ') {
             if reply_parent.is_none() {
-                if let Some((channelstr,msgstr)) = str1.split_once(" ") {
+                if let Some((channelstr,msgstr)) = str1.split_once(' ') {
                     Some((channelstr,msgstr))
                 } 
                 else { None }
-            } else {
-                if let Some((_,str2)) = str1.split_once(" ") {
-                    if let Some((channelstr,msgstr)) = str2.split_once(" ") {
-                    Some((channelstr,msgstr))
-                    } 
-                    else { None }
+            } else if let Some((_,str2)) = str1.split_once(' ') {
+                if let Some((channelstr,msgstr)) = str2.split_once(' ') {
+                Some((channelstr,msgstr))
                 } 
                 else { None }
-            }
+            } else { None }
         }
         else { None };
 
@@ -136,7 +128,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                 botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, format!("Not a Joined Channel : {}",trgchnl.to_string()))
+                .say_in_reply_to(&msg, format!("Not a Joined Channel : {}",trgchnl))
                 .await;
 
 

From 97d76ea088a00e8f9231be78db0dc5f1a9c05a13 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sat, 23 Mar 2024 22:40:06 -0400
Subject: [PATCH 43/98] added ts to experiment

---
 Cargo.lock                               |  5 +--
 Cargo.toml                               |  1 +
 src/custom/experimental/experiment002.rs | 43 ++++++++++++++++++++----
 3 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 18195c8..018b9dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -122,9 +122,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.34"
+version = "0.4.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
+checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -196,6 +196,7 @@ version = "0.1.0"
 dependencies = [
  "async-trait",
  "casual_logger",
+ "chrono",
  "dotenv",
  "futures",
  "rand",
diff --git a/Cargo.toml b/Cargo.toml
index 87f8cfa..f4c7751 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ rand = { version = "0.8.5", features = [] }
 futures = "0.3"
 async-trait = "0.1.77"
 casual_logger = "0.6.5"
+chrono = "0.4.35"
 
 [lib]
 name = "bot_lib"
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index ff18642..2a97b30 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -13,6 +13,8 @@
 // use rand::Rng;
 use std::sync::Arc;
 
+use chrono::{TimeZone,Local};
+
 use twitch_irc::message::PrivmsgMessage;
 
 // use crate::core::botinstance::ChType::Channel;
@@ -71,8 +73,18 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
     ;
 
 
-    let reply_parent_usr = if let Some(Some(reply)) = msg.source.tags.0.get("reply-thread-parent-user-login") {
-        Some(reply)
+    // let reply_parent_usr = if let Some(Some(reply)) = msg.source.tags.0.get("reply-thread-parent-user-login") {
+    //     Some(reply)
+    //     } else { None }
+    // ;
+
+    let reply_parent_ts = if let Some(Some(replyts)) = msg.source.tags.0.get("tmi-sent-ts") {
+
+        let a: i64 = replyts.parse().unwrap();
+        let b = Local.timestamp_millis_opt(a).unwrap();
+        // println!("Output : {}",b.to_string());
+        // println!("Formatted : {}",b.format("%m-%d %H:%M") );
+        Some(b.format("%m-%d %H:%M"))
         } else { None }
     ;
 
@@ -150,14 +162,33 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                 [ ] Get Target Channel - trgchnl
              */
 
+             // reply_parent_ts
             
             let newoutmsg = if let Some(srcmsg) = reply_parent {
 
-                format!("{} from #{} says {} . Replying to: {} : {}",
-                    msg.sender.name,msg.channel_login,outmsg, reply_parent_usr.unwrap(),srcmsg)
+                // format!("{} from #{} says {} . Replying to: {} : {}",
+                //     msg.sender.name,msg.channel_login,outmsg, reply_parent_usr.unwrap(),srcmsg)
+                // format!("{} from #{} says {} @ {} {} : {}",
+                //     msg.sender.name,
+                //     msg.channel_login,
+                //     outmsg,
+                //     reply_parent_ts.unwrap(), 
+                //     reply_parent_usr.unwrap(),
+                //     srcmsg)
+                format!("{} {} @ {} : {}",
+                    reply_parent_ts.unwrap(),
+                    msg.sender.name,
+                    msg.channel_login,
+                    srcmsg)
             } else {
-                format!("{} from #{} says : {}",
-                    msg.sender.name,msg.channel_login, outmsg)
+                // format!("{} from #{} says : {}",
+                //     msg.sender.name,
+                //     msg.channel_login, 
+                //     outmsg)
+                format!("in {} - {} : {}",
+                    msg.channel_login,
+                    msg.sender.name, 
+                    outmsg)
             };
 
             // uses chat.say_in_reply_to() for the bot controls for messages

From 616d1f564fe5ecd33e532ecc7a84775599d41b5c Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 14:09:08 -0400
Subject: [PATCH 44/98] reorg botactions.rs

---
 src/core/bot_actions.rs                  | 29 +++++++++++++++++-------
 src/core/botinstance.rs                  |  3 ++-
 src/core/botmodules.rs                   |  3 ++-
 src/core/identity.rs                     |  3 ++-
 src/custom/experimental/experiment001.rs |  3 ++-
 src/custom/experimental/experiment002.rs |  3 ++-
 6 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index 2e6b456..474291c 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -1,18 +1,31 @@
+
+use twitch_irc::message::PrivmsgMessage;
+use std::sync::Arc;
+// use tokio::sync::{Mutex, RwLock};
+use tokio::sync::RwLock;
+
+use crate::core::botinstance::BotInstance;
+
+
+pub type BotAR = Arc<RwLock<BotInstance>>;
+
+
+pub struct ExecBodyParams {
+    bot : BotAR,
+    msg : PrivmsgMessage,
+    // parent_act : BotAction , 
+}
+
 pub mod actions_util {
 
+    use super::*;
+
     use std::boxed::Box;
     use std::future::Future;
     use std::pin::Pin;
-    use std::sync::Arc;
 
-    use tokio::sync::{Mutex, RwLock};
 
-    use twitch_irc::message::PrivmsgMessage;
-
-    use crate::core::botinstance::BotInstance;
-
-    pub type BotAM = Arc<Mutex<BotInstance>>;
-    pub type BotAR = Arc<RwLock<BotInstance>>;
+    // pub type BotAM = Arc<Mutex<BotInstance>>;
 
     pub type ExecBody = Box<
         dyn Fn(BotAR, PrivmsgMessage) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index c5b6dca..15f16a1 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -17,7 +17,8 @@ use casual_logger::Log;
 
 use crate::core::ratelimiter::RateLimiter;
 
-use crate::core::bot_actions::actions_util::BotAR;
+// use crate::core::bot_actions::actions_util::BotAR;
+use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::ModulesManager;
 use crate::core::identity::{IdentityManager, Permissible,self};
 
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index f9d7ff0..d0028e3 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -32,7 +32,8 @@ use tokio::sync::RwLock;
 
 use async_trait::async_trait;
 
-use self::bot_actions::actions_util::BotAR;
+// use self::bot_actions::actions_util::BotAR;
+use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::actions_util;
 use crate::core::botinstance::{BotInstance, Channel,ChangeResult};
 use crate::core::botlog;
diff --git a/src/core/identity.rs b/src/core/identity.rs
index e816e9f..4243d26 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -7,7 +7,8 @@ use twitch_irc::message::PrivmsgMessage;
 
 use casual_logger::Log;
 
-use crate::core::bot_actions::actions_util::{self, BotAR};
+use crate::core::bot_actions::actions_util;
+use crate::core::bot_actions::BotAR;
 use crate::core::botinstance::{Channel,ChangeResult};
 use crate::core::botlog;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index f83693a..9b2c174 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -19,7 +19,8 @@ use twitch_irc::message::PrivmsgMessage;
 use crate::core::botinstance::Channel;
 use crate::core::botlog;
 
-use crate::core::bot_actions::actions_util::{self, BotAR};
+use crate::core::bot_actions::actions_util;
+use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
 
 use crate::core::identity::UserRole::*;
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 2a97b30..2dd63f4 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -24,7 +24,8 @@ use crate::core::botlog;
 
 use casual_logger::Log;
 
-use crate::core::bot_actions::actions_util::{self, BotAR};
+use crate::core::bot_actions::actions_util;
+use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
 use crate::core::identity::UserRole::*;

From 203f6af869787e6a96ef07b2073d052e40576482 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 14:38:09 -0400
Subject: [PATCH 45/98] ExecBodyParams

---
 src/core/bot_actions.rs                  | 12 ++--
 src/core/botinstance.rs                  |  7 ++-
 src/core/botmodules.rs                   | 60 ++++++++++---------
 src/core/identity.rs                     | 76 +++++++++++++-----------
 src/custom/experimental/experiment001.rs | 41 +++++++------
 src/custom/experimental/experiment002.rs | 29 +++++----
 6 files changed, 124 insertions(+), 101 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index 474291c..ee589b4 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -11,8 +11,8 @@ pub type BotAR = Arc<RwLock<BotInstance>>;
 
 
 pub struct ExecBodyParams {
-    bot : BotAR,
-    msg : PrivmsgMessage,
+    pub bot : BotAR,
+    pub msg : PrivmsgMessage,
     // parent_act : BotAction , 
 }
 
@@ -28,13 +28,15 @@ pub mod actions_util {
     // pub type BotAM = Arc<Mutex<BotInstance>>;
 
     pub type ExecBody = Box<
-        dyn Fn(BotAR, PrivmsgMessage) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
+        // dyn Fn(BotAR, PrivmsgMessage) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
+        dyn Fn(ExecBodyParams) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
     >;
 
-    pub fn asyncbox<T>(f: fn(BotAR, PrivmsgMessage) -> T) -> ExecBody
+    // pub fn asyncbox<T>(f: fn(BotAR, PrivmsgMessage) -> T) -> ExecBody
+    pub fn asyncbox<T>(f: fn(ExecBodyParams) -> T) -> ExecBody
     where
         T: Future<Output = ()> + Send + 'static,
     {
-        Box::new(move |a, b| Box::pin(f(a, b)))
+        Box::new(move |a| Box::pin(f(a)))
     }
 }
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 15f16a1..a714d9a 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -46,6 +46,7 @@ pub enum ChangeResult {
 //simplifying from enum to struct
 pub struct Channel(pub String);
 
+use super::bot_actions::ExecBodyParams;
 use super::botmodules::StatusType;
 
 #[derive(Clone)]
@@ -452,7 +453,8 @@ impl BotInstance {
                                     );
 
                                     let a = Arc::clone(&bot);
-                                    c.execute(a, msg.clone()).await;
+                                    // c.execute(a, msg.clone()).await;
+                                    c.execute(ExecBodyParams { bot : a, msg : msg.clone() }).await;
 
                                     botlog::trace(
                                         "exit out of execution",
@@ -498,7 +500,8 @@ impl BotInstance {
 
                         } else {
                             let a = Arc::clone(&bot);
-                            l.execute(a, msg.clone()).await;
+                            // l.execute(a, msg.clone()).await;
+                            l.execute(ExecBodyParams { bot : a, msg : msg.clone()} ).await;
                         }
 
                     }
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index d0028e3..81f5ae0 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -35,6 +35,7 @@ use async_trait::async_trait;
 // use self::bot_actions::actions_util::BotAR;
 use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::actions_util;
+use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{BotInstance, Channel,ChangeResult};
 use crate::core::botlog;
 use crate::core::identity::{self, Permissible,IdentityManager};
@@ -70,7 +71,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     botc1.add_core_to_modmgr(Arc::clone(&mgr)).await;
     
-    async fn cmd_enable(bot: BotAR, msg: PrivmsgMessage) {
+    // async fn cmd_enable(bot: BotAR, msg: PrivmsgMessage) {
+    async fn cmd_enable(params : ExecBodyParams) {
         /*
             There should be additional validation checks
             - BotAdmins can only run instance level (-i) enables
@@ -108,7 +110,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let (arg1, arg2) = {
 
-            let mut argv = msg.message_text.split(' ');
+            let mut argv = params.msg.message_text.split(' ');
 
             argv.next(); // Skip the command name
 
@@ -134,14 +136,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
         // [x] requestor: String,
-        let requestor = msg.clone().sender.name;
+        let requestor = params.msg.clone().sender.name;
 
 
         // [x] requestor_badge: Option<ChatBadge>,
 
         let mut requestor_badge_mut: Option<ChatBadge> = None;
 
-        for b in &msg.badges {
+        for b in &params.msg.badges {
             if b.name == "moderator" {
                 requestor_badge_mut = Some(ChatBadge::Mod);
             } else if b.name == "broadcaster" {
@@ -161,20 +163,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         // if let None = trg_module {
         if trg_module.is_none() {
 
-            let botlock = bot.read().await;
+            let botlock = params.bot.read().await;
             
             let outmsg = "uuh You need to pass a module";
 
             botlog::debug(
                 outmsg,
                 Some("botmodules.rs > cmd_enable()".to_string()),
-                Some(&msg),
+                Some(&params.msg),
             );
     
             botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, outmsg.to_string())
+                .say_in_reply_to(&params.msg, outmsg.to_string())
                 .await;
 
             return;
@@ -184,7 +186,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         // [x] trg_level: StatusLvl,
 
-        let currchnl = msg.channel_login.to_lowercase();
+        let currchnl = params.msg.channel_login.to_lowercase();
 
         let trg_level = 
             if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
@@ -194,7 +196,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         
     
-        let botlock = bot.read().await;
+        let botlock = params.bot.read().await;
         let modmgr = Arc::clone(&botlock.botmodules);
         let id = botlock.get_identity();
 
@@ -217,7 +219,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         botlock
             .botmgrs
             .chat
-            .say_in_reply_to(&msg, outmsg.to_string())
+            .say_in_reply_to(&params.msg, outmsg.to_string())
             .await;
 
 
@@ -244,7 +246,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     botc1.add_core_to_modmgr(Arc::clone(&mgr)).await;
     
-    async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) {
+    // async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) {
+    async fn cmd_disable(params : ExecBodyParams) {
         /*
             There should be additional validation checks
             - BotAdmins can only run instance level (-i) disables and (-f) force disable
@@ -284,7 +287,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let (arg1, arg2) = {
 
-            let mut argv = msg.message_text.split(' ');
+            let mut argv = params.msg.message_text.split(' ');
 
             argv.next(); // Skip the command name
 
@@ -312,14 +315,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
         // [x] requestor: String,
-        let requestor = msg.clone().sender.name;
+        let requestor = params.msg.clone().sender.name;
 
 
         // [x] requestor_badge: Option<ChatBadge>,
 
         let mut requestor_badge_mut: Option<ChatBadge> = None;
 
-        for b in &msg.badges {
+        for b in &params.msg.badges {
             if b.name == "moderator" {
                 requestor_badge_mut = Some(ChatBadge::Mod);
             } else if b.name == "broadcaster" {
@@ -338,20 +341,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         // if let None = trg_module {
         if trg_module.is_none() {
 
-            let botlock = bot.read().await;
+            let botlock = params.bot.read().await;
             
             let outmsg = "uuh You need to pass a module";
 
             botlog::debug(
                 outmsg,
                 Some("botmodules.rs > cmd_disable()".to_string()),
-                Some(&msg),
+                Some(&params.msg),
             );
     
             botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, outmsg.to_string())
+                .say_in_reply_to(&params.msg, outmsg.to_string())
                 .await;
 
             return;
@@ -362,7 +365,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         
         // [x] trg_level: StatusLvl,
 
-        let currchnl = msg.channel_login.to_lowercase();
+        let currchnl = params.msg.channel_login.to_lowercase();
 
         let trg_level = 
             if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
@@ -372,7 +375,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 
-        let botlock = bot.read().await;
+        let botlock = params.bot.read().await;
         let modmgr = Arc::clone(&botlock.botmodules);
         let id = botlock.get_identity();
 
@@ -397,7 +400,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         botlock
             .botmgrs
             .chat
-            .say_in_reply_to(&msg, outmsg.to_string())
+            .say_in_reply_to(&params.msg, outmsg.to_string())
             .await;
     
 
@@ -461,10 +464,11 @@ pub enum BotAction {
 }
 
 impl BotAction {
-    pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
+    // pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
+    pub async fn execute(&self, params : ExecBodyParams) {
         match self {
-            BotAction::L(a) => a.execute(m, n).await,
-            BotAction::C(a) => a.execute(m, n).await,
+            BotAction::L(a) => a.execute(params).await,
+            BotAction::C(a) => a.execute(params).await,
             _ => (),
         }
     }
@@ -488,8 +492,9 @@ pub struct BotCommand {
 }
 
 impl BotCommand {
-    pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
-        (*self.exec_body)(m, n).await;
+    // pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
+    pub async fn execute(&self, params : ExecBodyParams) {
+        (*self.exec_body)(params).await;
     }
 }
 
@@ -524,8 +529,9 @@ pub struct Listener {
 }
 
 impl Listener {
-    pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
-        (self.exec_body)(m, n).await;
+    // pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
+    pub async fn execute(&self, params : ExecBodyParams) {
+        (self.exec_body)(params).await;
     }
 }
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 4243d26..973ebe4 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -9,6 +9,7 @@ use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util;
 use crate::core::bot_actions::BotAR;
+use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{Channel,ChangeResult};
 use crate::core::botlog;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
@@ -71,11 +72,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // tempb.add_to_modmgr(Arc::clone(&mgr)).await;
     tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
-    async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) {
+    // async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) {
+    async fn cmd_promote(params : ExecBodyParams) {
         botlog::trace(
             "Called cmd promote",
             Some("identity.rs > cmd_prommote()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
         // -- If the BotCommand.command was called (e.g., promote) & required roles were validated OUTSIDE of this call
@@ -104,16 +106,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-        //  println!("{}",msg.message_text);
+        //  println!("{}",params.msg.message_text);
         botlog::trace(
-            format!("Twich Message > {}", msg.message_text).as_str(),
+            format!("Twich Message > {}", params.msg.message_text).as_str(),
             Some("identity.rs > cmd_promote()".to_string()),
             None,
         );
 
-        let sendername = msg.clone().sender.name;
+        let sendername = params.msg.clone().sender.name;
 
-        let mut argv = msg.message_text.split(' ');
+        let mut argv = params.msg.message_text.split(' ');
 
         argv.next(); // Skip the command name
 
@@ -123,7 +125,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let mut sender_badge: Option<ChatBadge> = None;
 
-        for b in &msg.badges {
+        for b in &params.msg.badges {
             if b.name == "moderator" {
                 sender_badge = Some(ChatBadge::Mod);
             } else if b.name == "broadcaster" {
@@ -131,7 +133,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             }
         }
 
-        let targetchnl = msg.channel_login.to_lowercase();
+        let targetchnl = params.msg.channel_login.to_lowercase();
 
         /*
 
@@ -149,7 +151,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         // [x] Get a required lock first
 
-        let botlock = bot.read().await;
+        let botlock = params.bot.read().await;
         let id = botlock.get_identity();
         let idlock = id.read().await;
 
@@ -209,13 +211,13 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         botlog::debug(
             outmsg.as_str(),
             Some("identity.rs > cmd_prommote()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
         botlock
             .botmgrs
             .chat
-            .say_in_reply_to(&msg, outmsg.to_string())
+            .say_in_reply_to(&params.msg, outmsg.to_string())
             .await;
 
         botlog::trace(
@@ -244,11 +246,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // add_core_to_modmgr
     tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
-    async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) {
+    // async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) {
+    async fn cmd_demote(params : ExecBodyParams) {
         botlog::debug(
             "Called cmd demote",
             Some("identity.rs > cmd_demote()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
         Log::flush();
 
@@ -281,7 +284,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         // [x] Unwraps arguments from message
 
         let (arg1, _arg2) = {
-            let mut argv = msg.message_text.split(' ');
+            let mut argv = params.msg.message_text.split(' ');
 
             argv.next(); // Skip the command name
 
@@ -320,11 +323,11 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-        let sendername = msg.clone().sender.name;
+        let sendername = params.msg.clone().sender.name;
 
         let mut sender_badge_mut: Option<ChatBadge> = None;
 
-        for b in &msg.badges {
+        for b in &params.msg.badges {
             if b.name == "moderator" {
                 sender_badge_mut = Some(ChatBadge::Mod);
             } else if b.name == "broadcaster" {
@@ -336,7 +339,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let targetusr = arg1;
 
-        let targetchnl = msg.channel_login.to_lowercase();
+        let targetchnl = params.msg.channel_login.to_lowercase();
 
         /*
 
@@ -350,7 +353,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         // [x] Get a required lock first
 
-        let botlock = bot.read().await;
+        let botlock = params.bot.read().await;
         let id = botlock.get_identity();
         let idlock = id.read().await;
 
@@ -408,13 +411,13 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         botlog::debug(
             outmsg.as_str(),
             Some("identity.rs > cmd_demote()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
         botlock
             .botmgrs
             .chat
-            .say_in_reply_to(&msg, outmsg.to_string())
+            .say_in_reply_to(&params.msg, outmsg.to_string())
             .await;
     }
 
@@ -436,11 +439,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // add_core_to_modmgr
     tempcomm.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
-    async fn getroles(bot: BotAR, msg: PrivmsgMessage) {
+    // async fn getroles(bot: BotAR, msg: PrivmsgMessage) {
+    async fn getroles(params : ExecBodyParams) {
         botlog::debug(
             "Called cmd getroles",
             Some("identity.rs > cmd_getroles()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
         /*
@@ -451,7 +455,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-        let mut argv = msg.message_text.split(' ');
+        let mut argv = params.msg.message_text.split(' ');
 
         argv.next(); // Skip the command name
 
@@ -466,7 +470,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let targetchnl = arg2;
 
-        let botlock = bot.read().await;
+        let botlock = params.bot.read().await;
 
         let id = botlock.get_identity();
 
@@ -478,7 +482,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 idlock
                     .getspecialuserroles(
                         String::from(targetuser),
-                        Some(Channel(msg.channel_login.to_lowercase())),
+                        Some(Channel(params.msg.channel_login.to_lowercase())),
                     )
                     .await
             }
@@ -486,7 +490,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 // [x] gets special roles for caller
                 let callersproles = idlock
                     .getspecialuserroles(
-                        msg.sender.name.to_lowercase(),
+                        params.msg.sender.name.to_lowercase(),
                         Some(Channel(targetchnl.to_lowercase().to_string())),
                     )
                     .await;
@@ -508,7 +512,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     idlock
                         .getspecialuserroles(
                             String::from(targetuser),
-                            Some(Channel(msg.channel_login.to_lowercase())),
+                            Some(Channel(params.msg.channel_login.to_lowercase())),
                         )
                         .await
                 }
@@ -518,17 +522,17 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         botlog::debug(
             &format!("User roles of Target Chatter >> {:?}", sproles),
             Some("identity.rs > init > getroles()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
         botlog::trace(
             // &format!("Evaluating special roles"),
             "Evaluating special roles",
             Some("identity.rs > init > getroles()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
-        let outmsg = if ((targetuser.to_lowercase() == msg.channel_login.to_lowercase())
+        let outmsg = if ((targetuser.to_lowercase() == params.msg.channel_login.to_lowercase())
             && arg2.is_none())
             || (arg2.is_some() && arg2.unwrap() == targetuser.to_lowercase())
         {
@@ -537,18 +541,18 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string();
 
             if sproles.contains(&UserRole::Mod(Channel(
-                msg.channel_login.to_lowercase(),
+                params.msg.channel_login.to_lowercase(),
             ))) || sproles.contains(&UserRole::SupMod(Channel(
-                msg.channel_login.to_lowercase(),
+                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(
-            msg.channel_login.to_lowercase(),
+            params.msg.channel_login.to_lowercase(),
         ))) || sproles.contains(&UserRole::SupMod(Channel(
-            msg.channel_login.to_lowercase(),
+            params.msg.channel_login.to_lowercase(),
         ))) || sproles.contains(&UserRole::BotAdmin)
         {
             format!("Target chatter's user roles are : {:?}", sproles)
@@ -559,10 +563,10 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         botlog::debug(
             format!("Chat Say Reply message : {}", outmsg).as_str(),
             Some("identity.rs > init > getroles()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
-        botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await;
+        botlock.botmgrs.chat.say_in_reply_to(&params.msg, outmsg).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
     }
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 9b2c174..bcdb9e5 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -15,6 +15,7 @@ use std::sync::Arc;
 
 use twitch_irc::message::PrivmsgMessage;
 
+use crate::core::bot_actions::ExecBodyParams;
 // use crate::core::botinstance::ChType::Channel;
 use crate::core::botinstance::Channel;
 use crate::core::botlog;
@@ -110,19 +111,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 }
 
-async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
+// async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
+    async fn good_girl(params : ExecBodyParams) {
     // [ ] Uses gen_ratio() to output bool based on a ratio probability .
     //   - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator)
     //   - More Info : https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_ratio
 
-    if msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
-        || msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
-    // if msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
+    if params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
+        || params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
+    // if params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
     {
         botlog::debug(
             "Good Girl Detected > Pausechamp",
             Some("experiments > goodgirl()".to_string()),
-            Some(&msg),
+            Some(&params.msg),
         );
 
         let rollwin = rand::thread_rng().gen_ratio(1, 1);
@@ -131,10 +133,10 @@ async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
             botlog::debug(
                 "Oh that's a good girl!",
                 Some("experiments > goodgirl()".to_string()),
-                Some(&msg),
+                Some(&params.msg),
             );
 
-            let bot = Arc::clone(&bot);
+            let bot = Arc::clone(&params.bot);
 
             let botlock = bot.read().await;
 
@@ -142,32 +144,34 @@ async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
             botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, String::from("GoodGirl xdd "))
+                .say_in_reply_to(&params.msg, String::from("GoodGirl xdd "))
                 .await;
         }
     }
 }
 
-async fn testy(mut _chat: BotAR, msg: PrivmsgMessage) {
+// async fn testy(mut _chat: BotAR, msg: PrivmsgMessage) {
+async fn testy(params : ExecBodyParams) {
     println!("testy triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
         "testy triggered!",
         Some("experiments > testy()".to_string()),
-        Some(&msg),
+        Some(&params.msg),
     );
 }
 
 
-async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
+// async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
+async fn babygirl(params : ExecBodyParams) {
     println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
         "babygirl triggered!",
         Some("experiments > babygirl()".to_string()),
-        Some(&msg),
+        Some(&params.msg),
     );
 
 
-    let bot = Arc::clone(&bot);
+    let bot = Arc::clone(&params.bot);
 
     let botlock = bot.read().await;
 
@@ -175,7 +179,7 @@ async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
     botlock
         .botmgrs
         .chat
-        .say_in_reply_to(&msg, String::from("16:13 notohh: cafdk"))
+        .say_in_reply_to(&params.msg, String::from("16:13 notohh: cafdk"))
         .await;
 
 
@@ -184,7 +188,7 @@ async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
     botlock
     .botmgrs
     .chat
-    .say_in_reply_to(&msg, String::from("16:13 notohh: have fun eating princess"))
+    .say_in_reply_to(&params.msg, String::from("16:13 notohh: have fun eating princess"))
     .await;
 
 
@@ -193,7 +197,7 @@ async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
     botlock
     .botmgrs
     .chat
-    .say_in_reply_to(&msg, String::from("16:13 notohh: baby girl"))
+    .say_in_reply_to(&params.msg, String::from("16:13 notohh: baby girl"))
     .await;
 
 
@@ -202,12 +206,13 @@ async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
 
 
 
-async fn routinelike(_bot: BotAR, msg: PrivmsgMessage) {
+// async fn routinelike(_bot: BotAR, msg: PrivmsgMessage) {
+async fn routinelike(params : ExecBodyParams) {
     println!("routinelike triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
         "routinelike triggered!",
         Some("experiments > routinelike()".to_string()),
-        Some(&msg),
+        Some(&params.msg),
     );
 
     // spawn an async block that runs independently from others
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 2dd63f4..8799f5a 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -17,6 +17,7 @@ use chrono::{TimeZone,Local};
 
 use twitch_irc::message::PrivmsgMessage;
 
+use crate::core::bot_actions::ExecBodyParams;
 // use crate::core::botinstance::ChType::Channel;
 use crate::core::botinstance::Channel;
 // use ChType::Channel;
@@ -61,14 +62,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 }
 
 
-async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
+// async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
+async fn sayout(params : ExecBodyParams) {
+
 
     /*
         usage :
         <target channel> <message>
      */
 
-    let reply_parent = if let Some(Some(reply)) = msg.source.tags.0.get("reply-parent-msg-body") {
+    let reply_parent = if let Some(Some(reply)) = params.msg.source.tags.0.get("reply-parent-msg-body") {
             Some(reply)
         } else { None }
     ;
@@ -79,7 +82,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
     //     } else { None }
     // ;
 
-    let reply_parent_ts = if let Some(Some(replyts)) = msg.source.tags.0.get("tmi-sent-ts") {
+    let reply_parent_ts = if let Some(Some(replyts)) = params.msg.source.tags.0.get("tmi-sent-ts") {
 
         let a: i64 = replyts.parse().unwrap();
         let b = Local.timestamp_millis_opt(a).unwrap();
@@ -93,7 +96,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 
 
     let argrslt = 
-        if let Some((_,str1)) = msg.message_text.split_once(' ') {
+        if let Some((_,str1)) = params.msg.message_text.split_once(' ') {
             if reply_parent.is_none() {
                 if let Some((channelstr,msgstr)) = str1.split_once(' ') {
                     Some((channelstr,msgstr))
@@ -114,7 +117,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
     match argrslt {
         Some((trgchnl,outmsg)) => {
 
-            let bot = Arc::clone(&bot);
+            let bot = Arc::clone(&params.bot);
 
             let botlock = bot.read().await;
 
@@ -141,7 +144,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                 botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, format!("Not a Joined Channel : {}",trgchnl))
+                .say_in_reply_to(&params.msg, format!("Not a Joined Channel : {}",trgchnl))
                 .await;
 
 
@@ -178,8 +181,8 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                 //     srcmsg)
                 format!("{} {} @ {} : {}",
                     reply_parent_ts.unwrap(),
-                    msg.sender.name,
-                    msg.channel_login,
+                    params.msg.sender.name,
+                    params.msg.channel_login,
                     srcmsg)
             } else {
                 // format!("{} from #{} says : {}",
@@ -187,8 +190,8 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
                 //     msg.channel_login, 
                 //     outmsg)
                 format!("in {} - {} : {}",
-                    msg.channel_login,
-                    msg.sender.name, 
+                    params.msg.channel_login,
+                    params.msg.sender.name, 
                     outmsg)
             };
 
@@ -206,10 +209,10 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
             botlog::debug(
                 "sayout had issues trying to parse arguments",
                 Some("experiment002 > sayout".to_string()),
-                Some(&msg),
+                Some(&params.msg),
             );
 
-            let bot = Arc::clone(&bot);
+            let bot = Arc::clone(&params.bot);
 
             let botlock = bot.read().await;
 
@@ -217,7 +220,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
             botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&msg, String::from("Invalid arguments"))
+                .say_in_reply_to(&params.msg, String::from("Invalid arguments"))
                 .await;
 
         },

From 7e5e43fec3cb16af2b8cbd3b8c6708a786517761 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 15:46:08 -0400
Subject: [PATCH 46/98] parentact to ExecBodyParams

---
 src/core/bot_actions.rs |  6 +++--
 src/core/botinstance.rs | 50 +++++++++++++++++++++++++++++------------
 src/core/botmodules.rs  | 17 ++++++++++----
 src/main.rs             |  6 ++++-
 4 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index ee589b4..243d2d9 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -6,14 +6,16 @@ use tokio::sync::RwLock;
 
 use crate::core::botinstance::BotInstance;
 
+use super::botmodules::BotAction;
+
 
 pub type BotAR = Arc<RwLock<BotInstance>>;
-
+pub type ActAR = Arc<RwLock<BotAction>>;
 
 pub struct ExecBodyParams {
     pub bot : BotAR,
     pub msg : PrivmsgMessage,
-    // parent_act : BotAction , 
+    pub parent_act : ActAR , 
 }
 
 pub mod actions_util {
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index a714d9a..5cdc60a 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -47,7 +47,7 @@ pub enum ChangeResult {
 pub struct Channel(pub String);
 
 use super::bot_actions::ExecBodyParams;
-use super::botmodules::StatusType;
+use super::botmodules::{BotAction, StatusType};
 
 #[derive(Clone)]
 pub struct BotManagers {
@@ -264,16 +264,6 @@ impl BotInstance {
 
         // // [ ] #todo Need to run through all Listener Bodies for Enabled Modules for the context of the message (e.g., ModStatus is Enabled in the context for the channel)
 
-        let botlock = bot.read().await;
-        let actsdb = Arc::clone(&botlock.botmodules.botactions);
-        let actsdblock = actsdb.read().await;
-
-        botlog::debug(
-            format!("# of BotModules: {}", (*actsdblock).len()).as_str(),
-            Some("BotInstance > listener_main_prvmsg()".to_string()),
-            Some(msg),
-        );
-
                             
         /*
             [ ] What we should do instead is : 
@@ -309,9 +299,30 @@ impl BotInstance {
             }, 
         };
 
+        
+        let botlock = bot.read().await;
+        let actsdb = Arc::clone(&botlock.botmodules.botactions);
+        let actsdblock = actsdb.read().await;
+
+        botlog::debug(
+            format!("# of BotModules: {}", (*actsdblock).len()).as_str(),
+            Some("BotInstance > listener_main_prvmsg()".to_string()),
+            Some(msg),
+        );
+
+
         for acts in (*actsdblock).values() {
+            
+
             for a in acts {
-                match a {
+
+                // let act_ar = Arc::new(RwLock::new(a));
+                // let act_ar_clone = Arc::clone(&act_ar);
+                let act_clone = Arc::clone(a);
+
+                // match a {
+                // match &(*act_ar_clone.read().await) {
+                match &(*act_clone.read().await) {
                     crate::core::botmodules::BotAction::C(c) => {
                         /*
                         BotCommand handling -
@@ -454,7 +465,13 @@ impl BotInstance {
 
                                     let a = Arc::clone(&bot);
                                     // c.execute(a, msg.clone()).await;
-                                    c.execute(ExecBodyParams { bot : a, msg : msg.clone() }).await;
+                                    // c.execute(ExecBodyParams { bot : a, msg : msg.clone() }).await;
+                                    c.execute(ExecBodyParams { 
+                                        bot : a, 
+                                        msg : msg.clone() ,
+                                        // parent_act : BotAction::C(c) ,
+                                        parent_act : Arc::clone(&act_clone),
+                                    }).await;
 
                                     botlog::trace(
                                         "exit out of execution",
@@ -501,7 +518,12 @@ impl BotInstance {
                         } else {
                             let a = Arc::clone(&bot);
                             // l.execute(a, msg.clone()).await;
-                            l.execute(ExecBodyParams { bot : a, msg : msg.clone()} ).await;
+                            l.execute(ExecBodyParams { 
+                                bot : a, 
+                                msg : msg.clone() , 
+                                // parent_act : BotAction::L(l) ,
+                                parent_act : Arc::clone(&act_clone),
+                            } ).await;
                         }
 
                     }
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 81f5ae0..3796d82 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -573,10 +573,11 @@ impl BotActionTrait for Listener {
 pub struct Routine {}
 
 type StatusdbEntry = (ModGroup, Vec<StatusType>);
+type ModuleActions = Vec<Arc<RwLock<BotAction>>>;
 
 pub struct ModulesManager {
     statusdb: Arc<RwLock<HashMap<BotModule, StatusdbEntry>>>,
-    pub botactions: Arc<RwLock<HashMap<BotModule, Vec<BotAction>>>>,
+    pub botactions: Arc<RwLock<HashMap<BotModule, ModuleActions>>>,
 }
 
 /*
@@ -1329,12 +1330,20 @@ impl ModulesManager {
         //       Check All Other BotAction Command Names & Aliases to ensure they don't conflict
 
         async fn find_conflict_module(mgr: &ModulesManager, act: &BotAction) -> Option<BotModule> {
+
             if let BotAction::C(incmd) = act {
                 let actdb = mgr.botactions.read().await;
 
                 for (module, moduleactions) in &(*actdb) {
-                    for modact in moduleactions.iter() {
-                        if let BotAction::C(dbcmd) = &modact {
+
+
+                    // for modact in moduleactions.iter() {
+                        for modact_prelock in moduleactions.iter() {
+
+                        let modact = modact_prelock.read().await;
+
+                        // if let BotAction::C(dbcmd) = &modact {
+                        if let BotAction::C(dbcmd) = &(*modact) {
                             // At this point, there is an command incmd and looked up dbcmd
 
                             // [x] check if given botcommand c.command:String conflicts with any in botactions
@@ -1390,7 +1399,7 @@ impl ModulesManager {
         let mut a = self.botactions.write().await;
         let modactions = a.entry(in_module.clone()).or_insert(Vec::new());
 
-        modactions.push(in_action);
+        modactions.push(Arc::new(RwLock::new(in_action)));
 
         botlog::trace(
             format!(
diff --git a/src/main.rs b/src/main.rs
index 40b5598..6bc6c0f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -33,7 +33,11 @@ pub async fn main() {
 
         for acts in (*actsdb_lock).values() {
             for act in acts {
-                let outstr = match act {
+
+                let act_prelock = act;
+                let act = act_prelock.read().await;
+
+                let outstr = match &(*act) {
                     botmodules::BotAction::C(b) => {
                         format!("bot actions > Command : {}", b.command)
                     }

From ee0b9ee19661a4821819aedee628c9ad1eae3bab Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 16:59:50 -0400
Subject: [PATCH 47/98] (init) say require parent module

---
 src/core/botinstance.rs                  |  11 +-
 src/core/botmodules.rs                   | 127 ++++++++++++++++++-----
 src/core/chat.rs                         |  15 ++-
 src/core/identity.rs                     |  98 +++++++++++++++--
 src/custom/experimental/experiment001.rs | 100 +++++++++++++-----
 src/custom/experimental/experiment002.rs |  74 ++++++++++---
 6 files changed, 344 insertions(+), 81 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 5cdc60a..c09050a 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -412,7 +412,10 @@ impl BotInstance {
                                     let botlock = bot.read().await;
                                     let outstr =
                                         format!("sadg Module is disabled : {:?}",a);
-                                    botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
+                                    botlock.botmgrs.chat.say_in_reply_to(
+                                        msg, 
+                                        outstr,
+                                        c.module.clone()).await;
                                 } 
 
                                 return;
@@ -451,7 +454,11 @@ impl BotInstance {
                                     let botlock = bot.read().await;
                                     let outstr =
                                         "o7 a Mod. I kneel to serve! pepeKneel ".to_string();
-                                    botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await;
+                                    botlock.botmgrs.chat.say_in_reply_to(
+                                        msg, 
+                                        outstr,
+                                        c.module.clone(),
+                                    ).await;
                                 }
                             }
 
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 3796d82..87dd243 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -104,6 +104,22 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
+        /*
+        
+            Get parent module 
+
+         */
+
+         let params_clone = Arc::clone(&params.parent_act);
+         let actlock = params_clone.read().await;
+         let act = &(*actlock);
+         let parent_module = match act {
+             BotAction::C(c) => Some(&(*c).module),
+             BotAction::L(l) => Some(&(*l).module),
+             _ => None,
+         };
+
+
 
 
         // [x] Unwraps arguments from message
@@ -172,12 +188,17 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 Some("botmodules.rs > cmd_enable()".to_string()),
                 Some(&params.msg),
             );
-    
-            botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(&params.msg, outmsg.to_string())
-                .await;
+
+            // Only call Say if there is a parent module passed
+            if parent_module.is_some() {
+
+        
+                botlock
+                    .botmgrs
+                    .chat
+                    .say_in_reply_to(&params.msg, outmsg.to_string() , parent_module.unwrap().clone())
+                    .await;
+            }
 
             return;
 
@@ -216,11 +237,19 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             ChangeResult::Success(a) => format!("YAAY Success : {}",a),
         };
 
-        botlock
-            .botmgrs
-            .chat
-            .say_in_reply_to(&params.msg, outmsg.to_string())
-            .await;
+        
+            // Only call Say if there is a parent module passed
+            if parent_module.is_some() {
+
+
+                botlock
+                    .botmgrs
+                    .chat
+                    .say_in_reply_to(&params.msg, outmsg.to_string(),parent_module.unwrap().clone())
+                    .await;
+
+            }
+
 
 
     }
@@ -282,6 +311,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 3c. , and is -f (forced) , return a Success    
          */
 
+        /*
+            [x] Get the parent module
+        */
+
+        let params_clone = Arc::clone(&params.parent_act);
+        let actlock = params_clone.read().await;
+        let act = &(*actlock);
+        let parent_module = match act {
+            BotAction::C(c) => Some(&(*c).module),
+            BotAction::L(l) => Some(&(*l).module),
+            _ => None,
+        };
+
+
 
                  // [x] Unwraps arguments from message
 
@@ -350,13 +393,30 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 Some("botmodules.rs > cmd_disable()".to_string()),
                 Some(&params.msg),
             );
-    
-            botlock
+
+
+            // let params_clone = Arc::clone(&params.parent_act);
+            // let actlock = params_clone.read().await;
+            // let act = &(*actlock);
+            // let parent_module = match act {
+            //     BotAction::C(c) => Some(&(*c).module),
+            //     BotAction::L(l) => Some(&(*l).module),
+            //     _ => None,
+            // };
+
+
+
+            // Only call Say if there is a parent module passed
+            if parent_module.is_some() {
+
+                botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&params.msg, outmsg.to_string())
+                .say_in_reply_to(&params.msg, outmsg.to_string(),parent_module.unwrap().clone())
                 .await;
 
+            }
+
             return;
 
         }
@@ -397,11 +457,35 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             ChangeResult::Success(a) => format!("YAAY Success : {}",a),
         };
 
-        botlock
-            .botmgrs
-            .chat
-            .say_in_reply_to(&params.msg, outmsg.to_string())
-            .await;
+        
+        // let actlock = params.parent_act.read().await;
+        // let act = *actlock;
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(c.module),
+        //     BotAction::L(l) => Some(l.module),
+        //     _ => None,
+        // };
+
+
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
+
+        // Only call Say if there is a parent module passed
+        if parent_module.is_some() {
+
+            botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(&params.msg, outmsg.to_string(),parent_module.unwrap().clone())
+                .await;
+
+        }
     
 
 
@@ -413,13 +497,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 
 #[derive(Debug, Clone)]
-// pub enum BotModule {
-//     BotModule(String),
-// }
-
 pub struct BotModule(pub String);
 
-
 impl PartialEq for BotModule {
     fn eq(&self, other: &Self) -> bool {
         let BotModule(name1) = self.clone();
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 1ba85e7..d379472 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -21,6 +21,8 @@ use crate::core::botlog;
 
 use tokio::time::{sleep, Duration};
 
+use super::botmodules::BotModule;
+
 #[derive(Clone)]
 pub struct Chat {
     pub ratelimiters: Arc<Mutex<HashMap<Channel, RateLimiter>>>, // used to limit messages sent per channel
@@ -54,7 +56,8 @@ impl Chat {
 
 
 
-    async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
+    // async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
+    async fn send_botmsg(&self, msginput: BotMsgType<'_>, _ : BotModule) {
                 /*
         formats message before sending to TwitchIRC
 
@@ -159,16 +162,18 @@ impl Chat {
 
 
 
-    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
+    // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
+    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , parent_module : BotModule) {
 
-        self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg)).await;
+        self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , parent_module).await;
 
     }
 
-    pub async fn say(&self, channel_login: String, message: String) {
+    // pub async fn say(&self, channel_login: String, message: String) {
+    pub async fn say(&self, channel_login: String, message: String , parent_module : BotModule) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
-        self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message)).await;
+        self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message), parent_module).await;
     }
 
     async fn _me(&self, _: String, _: String) {
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 973ebe4..5c2ede2 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -12,6 +12,7 @@ use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{Channel,ChangeResult};
 use crate::core::botlog;
+use crate::core::botmodules::BotAction;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
 use dotenv::dotenv;
@@ -106,6 +107,21 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
+
+        /*
+            [x] Get the parent module
+        */
+
+        let params_clone = Arc::clone(&params.parent_act);
+        let actlock = params_clone.read().await;
+        let act = &(*actlock);
+        let parent_module = match act {
+            BotAction::C(c) => Some(&(*c).module),
+            BotAction::L(l) => Some(&(*l).module),
+            _ => None,
+        };
+
+
         //  println!("{}",params.msg.message_text);
         botlog::trace(
             format!("Twich Message > {}", params.msg.message_text).as_str(),
@@ -214,11 +230,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
-        botlock
-            .botmgrs
-            .chat
-            .say_in_reply_to(&params.msg, outmsg.to_string())
-            .await;
+        // Only call Say if there is a parent module passed
+        if parent_module.is_some() {
+
+
+            botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(
+                        &params.msg, 
+                        outmsg.to_string(),
+                        parent_module.unwrap().clone())
+                .await;
+
+        }
 
         botlog::trace(
             // &format!("End of cmd_promote()"),
@@ -281,6 +306,22 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
+
+        /*
+            [x] Get the parent module
+        */
+
+        let params_clone = Arc::clone(&params.parent_act);
+        let actlock = params_clone.read().await;
+        let act = &(*actlock);
+        let parent_module = match act {
+            BotAction::C(c) => Some(&(*c).module),
+            BotAction::L(l) => Some(&(*l).module),
+            _ => None,
+        };
+
+        
+
         // [x] Unwraps arguments from message
 
         let (arg1, _arg2) = {
@@ -414,11 +455,23 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
-        botlock
-            .botmgrs
-            .chat
-            .say_in_reply_to(&params.msg, outmsg.to_string())
-            .await;
+
+        // Only call Say if there is a parent module passed
+        if parent_module.is_some() {
+
+            botlock
+                .botmgrs
+                .chat
+                .say_in_reply_to(
+                    &params.msg, 
+                outmsg.to_string(),
+                parent_module.unwrap().clone())
+                .await;
+
+        }
+
+
+
     }
 
     let tempcomm = BotCommand {
@@ -455,6 +508,20 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
+        /*  
+            [x] Get the parent module
+        */
+
+        let params_clone = Arc::clone(&params.parent_act);
+        let actlock = params_clone.read().await;
+        let act = &(*actlock);
+        let parent_module = match act {
+            BotAction::C(c) => Some(&(*c).module),
+            BotAction::L(l) => Some(&(*l).module),
+            _ => None,
+        };
+        
+
         let mut argv = params.msg.message_text.split(' ');
 
         argv.next(); // Skip the command name
@@ -566,7 +633,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
-        botlock.botmgrs.chat.say_in_reply_to(&params.msg, outmsg).await;
+        if parent_module.is_some() {
+
+            botlock.botmgrs.chat.say_in_reply_to(
+                &params.msg, 
+                outmsg,
+                parent_module.unwrap().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
     }
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index bcdb9e5..dcd45a2 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -22,6 +22,7 @@ use crate::core::botlog;
 
 use crate::core::bot_actions::actions_util;
 use crate::core::bot_actions::BotAR;
+use crate::core::botmodules::BotAction;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
 
 use crate::core::identity::UserRole::*;
@@ -113,6 +114,19 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 // async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
     async fn good_girl(params : ExecBodyParams) {
+
+
+    let params_clone = Arc::clone(&params.parent_act);
+    let actlock = params_clone.read().await;
+    let act = &(*actlock);
+    let parent_module = match act {
+        BotAction::C(c) => Some(&(*c).module),
+        BotAction::L(l) => Some(&(*l).module),
+        _ => None,
+    };
+        
+
+
     // [ ] Uses gen_ratio() to output bool based on a ratio probability .
     //   - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator)
     //   - More Info : https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_ratio
@@ -140,12 +154,21 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let botlock = bot.read().await;
 
-            // uses chat.say_in_reply_to() for the bot controls for messages
-            botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(&params.msg, String::from("GoodGirl xdd "))
-                .await;
+
+            if parent_module.is_some() {
+
+                // uses chat.say_in_reply_to() for the bot controls for messages
+                botlock
+                    .botmgrs
+                    .chat
+                    .say_in_reply_to(
+                        &params.msg, 
+                        String::from("GoodGirl xdd "),
+                        parent_module.unwrap().clone()
+                    ).await;
+
+            }
+
         }
     }
 }
@@ -163,6 +186,22 @@ async fn testy(params : ExecBodyParams) {
 
 // async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
 async fn babygirl(params : ExecBodyParams) {
+
+        /*
+            [x] Get the parent module
+        */
+
+        let params_clone = Arc::clone(&params.parent_act);
+        let actlock = params_clone.read().await;
+        let act = &(*actlock);
+        let parent_module = match act {
+            BotAction::C(c) => Some(&(*c).module),
+            BotAction::L(l) => Some(&(*l).module),
+            _ => None,
+        };
+
+
+
     println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
         "babygirl triggered!",
@@ -175,30 +214,43 @@ async fn babygirl(params : ExecBodyParams) {
 
     let botlock = bot.read().await;
 
-    // uses chat.say_in_reply_to() for the bot controls for messages
-    botlock
+    if parent_module.is_some() {
+
+        // uses chat.say_in_reply_to() for the bot controls for messages
+        botlock
+            .botmgrs
+            .chat
+            .say_in_reply_to(
+                &params.msg, 
+                String::from("16:13 notohh: cafdk"),
+                parent_module.unwrap().clone()
+            ).await;
+
+
+        sleep(Duration::from_secs_f64(0.5)).await;
+
+        botlock
         .botmgrs
         .chat
-        .say_in_reply_to(&params.msg, String::from("16:13 notohh: cafdk"))
-        .await;
+        .say_in_reply_to(
+            &params.msg, 
+            String::from("16:13 notohh: have fun eating princess"),
+            parent_module.unwrap().clone()
+        ).await;
 
 
-    sleep(Duration::from_secs_f64(0.5)).await;
+        sleep(Duration::from_secs_f64(2.0)).await;
 
-    botlock
-    .botmgrs
-    .chat
-    .say_in_reply_to(&params.msg, String::from("16:13 notohh: have fun eating princess"))
-    .await;
+        botlock
+        .botmgrs
+        .chat
+        .say_in_reply_to(
+            &params.msg, 
+            String::from("16:13 notohh: baby girl"),
+            parent_module.unwrap().clone()
+        ).await;
 
-
-    sleep(Duration::from_secs_f64(2.0)).await;
-
-    botlock
-    .botmgrs
-    .chat
-    .say_in_reply_to(&params.msg, String::from("16:13 notohh: baby girl"))
-    .await;
+    }
 
 
 }
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 8799f5a..4709394 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -22,6 +22,7 @@ use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::Channel;
 // use ChType::Channel;
 use crate::core::botlog;
+use crate::core::botmodules::BotAction;
 
 use casual_logger::Log;
 
@@ -71,6 +72,24 @@ async fn sayout(params : ExecBodyParams) {
         <target channel> <message>
      */
 
+
+
+     
+        /*
+            [x] Get the parent module
+        */
+
+        let params_clone = Arc::clone(&params.parent_act);
+        let actlock = params_clone.read().await;
+        let act = &(*actlock);
+        let parent_module = match act {
+            BotAction::C(c) => Some(&(*c).module),
+            BotAction::L(l) => Some(&(*l).module),
+            _ => None,
+        };
+
+
+
     let reply_parent = if let Some(Some(reply)) = params.msg.source.tags.0.get("reply-parent-msg-body") {
             Some(reply)
         } else { None }
@@ -141,11 +160,19 @@ async fn sayout(params : ExecBodyParams) {
                 );
                 // return ;
 
-                botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(&params.msg, format!("Not a Joined Channel : {}",trgchnl))
-                .await;
+                if parent_module.is_some() {
+
+                    
+                    botlock
+                    .botmgrs
+                    .chat
+                    .say_in_reply_to(
+                        &params.msg, 
+                        format!("Not a Joined Channel : {}",trgchnl),
+                        parent_module.unwrap().clone()
+                    ).await;
+
+                }
 
 
             }
@@ -195,12 +222,21 @@ async fn sayout(params : ExecBodyParams) {
                     outmsg)
             };
 
-            // uses chat.say_in_reply_to() for the bot controls for messages
-            botlock
-                .botmgrs
-                .chat
-                .say(trgchnl.to_string(), newoutmsg.to_string())
-                .await;
+            
+            if parent_module.is_some() {
+
+
+                // uses chat.say_in_reply_to() for the bot controls for messages
+                botlock
+                    .botmgrs
+                    .chat
+                    .say(
+                        trgchnl.to_string(), 
+                        newoutmsg.to_string(),
+                    parent_module.unwrap().clone())
+                    .await;
+
+            }
 
 
 
@@ -216,12 +252,20 @@ async fn sayout(params : ExecBodyParams) {
 
             let botlock = bot.read().await;
 
-            // uses chat.say_in_reply_to() for the bot controls for messages
-            botlock
+
+            if parent_module.is_some() {
+                
+                // uses chat.say_in_reply_to() for the bot controls for messages
+                botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&params.msg, String::from("Invalid arguments"))
-                .await;
+                .say_in_reply_to(
+                    &params.msg, 
+                    String::from("Invalid arguments"),
+                    parent_module.unwrap().clone()
+                ).await;
+
+            }
 
         },
 

From 0eb43c87f2581d3309fd0d26a64088cb77fa0349 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 17:40:57 -0400
Subject: [PATCH 48/98] ExecBodyParams get_parent_module()

---
 src/core/bot_actions.rs                  | 53 +++++++++++++++++++++++-
 src/core/botmodules.rs                   | 36 ++++++++--------
 src/core/identity.rs                     | 51 ++++++++++++-----------
 src/custom/experimental/experiment001.rs | 42 ++++++++++---------
 src/custom/experimental/experiment002.rs | 24 ++++++-----
 5 files changed, 134 insertions(+), 72 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index 243d2d9..b1ce97f 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -6,7 +6,7 @@ use tokio::sync::RwLock;
 
 use crate::core::botinstance::BotInstance;
 
-use super::botmodules::BotAction;
+use super::botmodules::{BotAction, BotModule};
 
 
 pub type BotAR = Arc<RwLock<BotInstance>>;
@@ -18,6 +18,57 @@ pub struct ExecBodyParams {
     pub parent_act : ActAR , 
 }
 
+
+impl ExecBodyParams {
+
+    // pub async fn get_parent_module(&self) -> Arc<Option<BotModule>> {
+    pub async fn get_parent_module(&self) -> Option<BotModule> {
+
+    //     let params_clone = Arc::clone(&self.parent_act);
+    //     // let actlock = params_clone.read().await;
+    //     // let act = &(*actlock);
+    //     // let a = Arc::new(&act);
+    //     // let parent_module = match act {
+    //     // let parent_module = match &(*actlock) {
+    //         let parent_module = match &(*(params_clone.read().await)) {
+    //         BotAction::C(c) => Some(&(*c).module),
+    //         BotAction::L(l) => Some(&(*l).module),
+    //         _ => None,
+    //     };
+     
+    //     // Some(BotModule("Tester".to_string()))
+    //     let a = Arc::new(parent_module);
+    //     a
+
+
+        let parent_act = Arc::clone(&self.parent_act);
+        let parent_act_lock = parent_act.read().await;
+        let act = &(*parent_act_lock);
+        let parent_module = match act {
+            BotAction::C(c) => {
+                let temp = c.module.clone();
+                Some(temp)
+            },
+            BotAction::L(l) => {
+                let temp = l.module.clone();
+                Some(temp)
+            },
+            _ => None
+        };
+
+        // Arc::new(a)
+        parent_module
+        // let a = BotModule("hello".to_string());
+        // Arc::new(Some(a))
+        
+    }
+
+
+
+}
+
+
+
 pub mod actions_util {
 
     use super::*;
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 87dd243..de1a4a5 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -110,14 +110,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-         let params_clone = Arc::clone(&params.parent_act);
-         let actlock = params_clone.read().await;
-         let act = &(*actlock);
-         let parent_module = match act {
-             BotAction::C(c) => Some(&(*c).module),
-             BotAction::L(l) => Some(&(*l).module),
-             _ => None,
-         };
+        //  let params_clone = Arc::clone(&params.parent_act);
+        //  let actlock = params_clone.read().await;
+        //  let act = &(*actlock);
+        //  let parent_module = match act {
+        //      BotAction::C(c) => Some(&(*c).module),
+        //      BotAction::L(l) => Some(&(*l).module),
+        //      _ => None,
+        //  };
+
+        let parent_module = params.get_parent_module().await;
 
 
 
@@ -315,16 +317,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             [x] Get the parent module
         */
 
-        let params_clone = Arc::clone(&params.parent_act);
-        let actlock = params_clone.read().await;
-        let act = &(*actlock);
-        let parent_module = match act {
-            BotAction::C(c) => Some(&(*c).module),
-            BotAction::L(l) => Some(&(*l).module),
-            _ => None,
-        };
-
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
 
+        let parent_module = params.get_parent_module().await;
 
                  // [x] Unwraps arguments from message
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 5c2ede2..835fb0e 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -112,15 +112,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             [x] Get the parent module
         */
 
-        let params_clone = Arc::clone(&params.parent_act);
-        let actlock = params_clone.read().await;
-        let act = &(*actlock);
-        let parent_module = match act {
-            BotAction::C(c) => Some(&(*c).module),
-            BotAction::L(l) => Some(&(*l).module),
-            _ => None,
-        };
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
 
+        let parent_module = params.get_parent_module().await;
 
         //  println!("{}",params.msg.message_text);
         botlog::trace(
@@ -311,15 +312,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             [x] Get the parent module
         */
 
-        let params_clone = Arc::clone(&params.parent_act);
-        let actlock = params_clone.read().await;
-        let act = &(*actlock);
-        let parent_module = match act {
-            BotAction::C(c) => Some(&(*c).module),
-            BotAction::L(l) => Some(&(*l).module),
-            _ => None,
-        };
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
 
+        let parent_module = params.get_parent_module().await;
         
 
         // [x] Unwraps arguments from message
@@ -512,15 +514,16 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             [x] Get the parent module
         */
 
-        let params_clone = Arc::clone(&params.parent_act);
-        let actlock = params_clone.read().await;
-        let act = &(*actlock);
-        let parent_module = match act {
-            BotAction::C(c) => Some(&(*c).module),
-            BotAction::L(l) => Some(&(*l).module),
-            _ => None,
-        };
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
         
+        let parent_module = params.get_parent_module().await;
 
         let mut argv = params.msg.message_text.split(' ');
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index dcd45a2..8a93cc6 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -116,16 +116,17 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     async fn good_girl(params : ExecBodyParams) {
 
 
-    let params_clone = Arc::clone(&params.parent_act);
-    let actlock = params_clone.read().await;
-    let act = &(*actlock);
-    let parent_module = match act {
-        BotAction::C(c) => Some(&(*c).module),
-        BotAction::L(l) => Some(&(*l).module),
-        _ => None,
-    };
-        
+    // let params_clone = Arc::clone(&params.parent_act);
+    // let actlock = params_clone.read().await;
+    // let act = &(*actlock);
+    // let parent_module = match act {
+    //     BotAction::C(c) => Some(&(*c).module),
+    //     BotAction::L(l) => Some(&(*l).module),
+    //     _ => None,
+    // };
 
+    
+    let parent_module = params.get_parent_module().await;
 
     // [ ] Uses gen_ratio() to output bool based on a ratio probability .
     //   - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator)
@@ -191,16 +192,19 @@ async fn babygirl(params : ExecBodyParams) {
             [x] Get the parent module
         */
 
-        let params_clone = Arc::clone(&params.parent_act);
-        let actlock = params_clone.read().await;
-        let act = &(*actlock);
-        let parent_module = match act {
-            BotAction::C(c) => Some(&(*c).module),
-            BotAction::L(l) => Some(&(*l).module),
-            _ => None,
-        };
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
 
 
+    
+        let parent_module = params.get_parent_module().await;
+
 
     println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
@@ -223,7 +227,7 @@ async fn babygirl(params : ExecBodyParams) {
             .say_in_reply_to(
                 &params.msg, 
                 String::from("16:13 notohh: cafdk"),
-                parent_module.unwrap().clone()
+                parent_module.clone().unwrap().clone()
             ).await;
 
 
@@ -235,7 +239,7 @@ async fn babygirl(params : ExecBodyParams) {
         .say_in_reply_to(
             &params.msg, 
             String::from("16:13 notohh: have fun eating princess"),
-            parent_module.unwrap().clone()
+            parent_module.clone().unwrap().clone()
         ).await;
 
 
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 4709394..fe603fd 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -79,14 +79,16 @@ async fn sayout(params : ExecBodyParams) {
             [x] Get the parent module
         */
 
-        let params_clone = Arc::clone(&params.parent_act);
-        let actlock = params_clone.read().await;
-        let act = &(*actlock);
-        let parent_module = match act {
-            BotAction::C(c) => Some(&(*c).module),
-            BotAction::L(l) => Some(&(*l).module),
-            _ => None,
-        };
+        // let params_clone = Arc::clone(&params.parent_act);
+        // let actlock = params_clone.read().await;
+        // let act = &(*actlock);
+        // let parent_module = match act {
+        //     BotAction::C(c) => Some(&(*c).module),
+        //     BotAction::L(l) => Some(&(*l).module),
+        //     _ => None,
+        // };
+
+    let parent_module = params.get_parent_module().await;
 
 
 
@@ -160,7 +162,7 @@ async fn sayout(params : ExecBodyParams) {
                 );
                 // return ;
 
-                if parent_module.is_some() {
+                if parent_module.clone().is_some() {
 
                     
                     botlock
@@ -169,7 +171,7 @@ async fn sayout(params : ExecBodyParams) {
                     .say_in_reply_to(
                         &params.msg, 
                         format!("Not a Joined Channel : {}",trgchnl),
-                        parent_module.unwrap().clone()
+                        parent_module.clone().unwrap().clone()
                     ).await;
 
                 }
@@ -223,7 +225,7 @@ async fn sayout(params : ExecBodyParams) {
             };
 
             
-            if parent_module.is_some() {
+            if parent_module.clone().is_some() {
 
 
                 // uses chat.say_in_reply_to() for the bot controls for messages

From 958aeea48e76094f88795068d7b1ccc814dcdf5a Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 18:14:08 -0400
Subject: [PATCH 49/98] execbodyparams passed to chat()

---
 src/core/bot_actions.rs                  | 24 +-----------
 src/core/botinstance.rs                  | 24 +++++++++++-
 src/core/botmodules.rs                   | 50 ++++++++++++------------
 src/core/chat.rs                         | 17 +++++---
 src/core/identity.rs                     | 13 +++---
 src/custom/experimental/experiment001.rs | 12 ++++--
 src/custom/experimental/experiment002.rs | 11 ++++--
 7 files changed, 82 insertions(+), 69 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index b1ce97f..d2d8d25 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -12,6 +12,7 @@ use super::botmodules::{BotAction, BotModule};
 pub type BotAR = Arc<RwLock<BotInstance>>;
 pub type ActAR = Arc<RwLock<BotAction>>;
 
+#[derive(Clone)]
 pub struct ExecBodyParams {
     pub bot : BotAR,
     pub msg : PrivmsgMessage,
@@ -21,26 +22,8 @@ pub struct ExecBodyParams {
 
 impl ExecBodyParams {
 
-    // pub async fn get_parent_module(&self) -> Arc<Option<BotModule>> {
     pub async fn get_parent_module(&self) -> Option<BotModule> {
 
-    //     let params_clone = Arc::clone(&self.parent_act);
-    //     // let actlock = params_clone.read().await;
-    //     // let act = &(*actlock);
-    //     // let a = Arc::new(&act);
-    //     // let parent_module = match act {
-    //     // let parent_module = match &(*actlock) {
-    //         let parent_module = match &(*(params_clone.read().await)) {
-    //         BotAction::C(c) => Some(&(*c).module),
-    //         BotAction::L(l) => Some(&(*l).module),
-    //         _ => None,
-    //     };
-     
-    //     // Some(BotModule("Tester".to_string()))
-    //     let a = Arc::new(parent_module);
-    //     a
-
-
         let parent_act = Arc::clone(&self.parent_act);
         let parent_act_lock = parent_act.read().await;
         let act = &(*parent_act_lock);
@@ -55,12 +38,7 @@ impl ExecBodyParams {
             },
             _ => None
         };
-
-        // Arc::new(a)
         parent_module
-        // let a = BotModule("hello".to_string());
-        // Arc::new(Some(a))
-        
     }
 
 
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index c09050a..dc5e70b 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -412,10 +412,20 @@ impl BotInstance {
                                     let botlock = bot.read().await;
                                     let outstr =
                                         format!("sadg Module is disabled : {:?}",a);
+
+                                    let params = ExecBodyParams {
+                                        bot : Arc::clone(&bot),
+                                        msg : (*msg).clone(),
+                                        parent_act : Arc::clone(&act_clone),
+
+                                    };
+
                                     botlock.botmgrs.chat.say_in_reply_to(
                                         msg, 
                                         outstr,
-                                        c.module.clone()).await;
+                                        // c.module.clone()
+                                        params,
+                                    ).await;
                                 } 
 
                                 return;
@@ -454,10 +464,20 @@ impl BotInstance {
                                     let botlock = bot.read().await;
                                     let outstr =
                                         "o7 a Mod. I kneel to serve! pepeKneel ".to_string();
+
+                                    
+                                    let params = ExecBodyParams {
+                                        bot : Arc::clone(&bot),
+                                        msg : (*msg).clone(),
+                                        parent_act : Arc::clone(&act_clone),
+
+                                    };
+
                                     botlock.botmgrs.chat.say_in_reply_to(
                                         msg, 
                                         outstr,
-                                        c.module.clone(),
+                                        // c.module.clone(),
+                                        params
                                     ).await;
                                 }
                             }
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index de1a4a5..b173e7b 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -198,8 +198,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 botlock
                     .botmgrs
                     .chat
-                    .say_in_reply_to(&params.msg, outmsg.to_string() , parent_module.unwrap().clone())
-                    .await;
+                    .say_in_reply_to(
+                        &params.msg, 
+                        outmsg.to_string() , 
+                        // parent_module.unwrap().clone()
+                        params.clone(),
+                    ).await;
             }
 
             return;
@@ -247,8 +251,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 botlock
                     .botmgrs
                     .chat
-                    .say_in_reply_to(&params.msg, outmsg.to_string(),parent_module.unwrap().clone())
-                    .await;
+                    .say_in_reply_to(
+                        &params.msg, 
+                        outmsg.to_string(),
+                        // parent_module.unwrap().clone()
+                        params.clone(),
+                    ).await;
 
             }
 
@@ -414,8 +422,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&params.msg, outmsg.to_string(),parent_module.unwrap().clone())
-                .await;
+                .say_in_reply_to(
+                    &params.msg, 
+                    outmsg.to_string(),
+                    // ,parent_module.unwrap().clone()
+                    params.clone()
+                ).await;
 
             }
 
@@ -459,24 +471,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             ChangeResult::Success(a) => format!("YAAY Success : {}",a),
         };
 
-        
-        // let actlock = params.parent_act.read().await;
-        // let act = *actlock;
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(c.module),
-        //     BotAction::L(l) => Some(l.module),
-        //     _ => None,
-        // };
-
-
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
 
         // Only call Say if there is a parent module passed
         if parent_module.is_some() {
@@ -484,8 +478,12 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             botlock
                 .botmgrs
                 .chat
-                .say_in_reply_to(&params.msg, outmsg.to_string(),parent_module.unwrap().clone())
-                .await;
+                .say_in_reply_to(
+                    &params.msg,
+                     outmsg.to_string(),
+                    //  parent_module.unwrap().clone()
+                    params.clone(),
+                ).await;
 
         }
     
diff --git a/src/core/chat.rs b/src/core/chat.rs
index d379472..8cc2cda 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -21,6 +21,7 @@ use crate::core::botlog;
 
 use tokio::time::{sleep, Duration};
 
+use super::bot_actions::ExecBodyParams;
 use super::botmodules::BotModule;
 
 #[derive(Clone)]
@@ -57,7 +58,7 @@ impl Chat {
 
 
     // async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
-    async fn send_botmsg(&self, msginput: BotMsgType<'_>, _ : BotModule) {
+    async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
                 /*
         formats message before sending to TwitchIRC
 
@@ -87,6 +88,12 @@ impl Chat {
             return ;
         }
 
+        /*
+            [ ] !! => 03.24 - Somewhere around here, we should be validating module for target channel
+        */
+
+        
+
         let rl = Arc::clone(&self.ratelimiters);
         let mut rllock = rl.lock().await;
 
@@ -163,17 +170,17 @@ impl Chat {
 
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
-    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , parent_module : BotModule) {
+    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
 
-        self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , parent_module).await;
+        self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;
 
     }
 
     // pub async fn say(&self, channel_login: String, message: String) {
-    pub async fn say(&self, channel_login: String, message: String , parent_module : BotModule) {
+    pub async fn say(&self, channel_login: String, message: String , params : ExecBodyParams) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
-        self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message), parent_module).await;
+        self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message), params).await;
     }
 
     async fn _me(&self, _: String, _: String) {
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 835fb0e..0be4dea 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -241,8 +241,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 .say_in_reply_to(
                         &params.msg, 
                         outmsg.to_string(),
-                        parent_module.unwrap().clone())
-                .await;
+                        // parent_module.unwrap().clone()
+                        params.clone(),
+                ).await;
 
         }
 
@@ -467,8 +468,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 .say_in_reply_to(
                     &params.msg, 
                 outmsg.to_string(),
-                parent_module.unwrap().clone())
-                .await;
+                    // parent_module.unwrap().clone()
+                    params.clone()
+                ).await;
 
         }
 
@@ -641,7 +643,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             botlock.botmgrs.chat.say_in_reply_to(
                 &params.msg, 
                 outmsg,
-                parent_module.unwrap().clone()
+                // parent_module.unwrap().clone()
+                params.clone()
             ).await;
 
         }
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 8a93cc6..54e6552 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -165,7 +165,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     .say_in_reply_to(
                         &params.msg, 
                         String::from("GoodGirl xdd "),
-                        parent_module.unwrap().clone()
+                        // parent_module.unwrap().clone()
+                        params.clone()
                     ).await;
 
             }
@@ -227,7 +228,8 @@ async fn babygirl(params : ExecBodyParams) {
             .say_in_reply_to(
                 &params.msg, 
                 String::from("16:13 notohh: cafdk"),
-                parent_module.clone().unwrap().clone()
+                // parent_module.clone().unwrap().clone()
+                params.clone()
             ).await;
 
 
@@ -239,7 +241,8 @@ async fn babygirl(params : ExecBodyParams) {
         .say_in_reply_to(
             &params.msg, 
             String::from("16:13 notohh: have fun eating princess"),
-            parent_module.clone().unwrap().clone()
+            // parent_module.clone().unwrap().clone()
+            params.clone()
         ).await;
 
 
@@ -251,7 +254,8 @@ async fn babygirl(params : ExecBodyParams) {
         .say_in_reply_to(
             &params.msg, 
             String::from("16:13 notohh: baby girl"),
-            parent_module.unwrap().clone()
+            // parent_module.unwrap().clone()
+            params.clone()
         ).await;
 
     }
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index fe603fd..be53ffa 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -171,7 +171,8 @@ async fn sayout(params : ExecBodyParams) {
                     .say_in_reply_to(
                         &params.msg, 
                         format!("Not a Joined Channel : {}",trgchnl),
-                        parent_module.clone().unwrap().clone()
+                        // parent_module.clone().unwrap().clone()
+                        params.clone(),
                     ).await;
 
                 }
@@ -235,8 +236,9 @@ async fn sayout(params : ExecBodyParams) {
                     .say(
                         trgchnl.to_string(), 
                         newoutmsg.to_string(),
-                    parent_module.unwrap().clone())
-                    .await;
+                    // parent_module.unwrap().clone()
+                        params.clone(),
+                    ).await;
 
             }
 
@@ -264,7 +266,8 @@ async fn sayout(params : ExecBodyParams) {
                 .say_in_reply_to(
                     &params.msg, 
                     String::from("Invalid arguments"),
-                    parent_module.unwrap().clone()
+                    // parent_module.unwrap().clone()
+                    params.clone()
                 ).await;
 
             }

From 6deac8e6c74699bcf09f4fbe630e1a99ea63ba7e Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 18:50:11 -0400
Subject: [PATCH 50/98] chat.send validates target channel module status

---
 Cargo.lock       | 12 ++++++++++++
 Cargo.toml       |  2 ++
 src/core/chat.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/Cargo.lock b/Cargo.lock
index 018b9dc..da35376 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -41,6 +41,17 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "async-recursion"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "async-trait"
 version = "0.1.77"
@@ -194,6 +205,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
 name = "forcebot_rs"
 version = "0.1.0"
 dependencies = [
+ "async-recursion",
  "async-trait",
  "casual_logger",
  "chrono",
diff --git a/Cargo.toml b/Cargo.toml
index f4c7751..f3f7724 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,9 +12,11 @@ twitch-irc = "5.0.1"
 rand = { version = "0.8.5", features = [] }
 futures = "0.3"
 async-trait = "0.1.77"
+async-recursion = "1.1.0"
 casual_logger = "0.6.5"
 chrono = "0.4.35"
 
+
 [lib]
 name = "bot_lib"
 path = "src/lib.rs"
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 8cc2cda..a2d5b2b 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -24,6 +24,9 @@ use tokio::time::{sleep, Duration};
 use super::bot_actions::ExecBodyParams;
 use super::botmodules::BotModule;
 
+
+use async_recursion::async_recursion;
+
 #[derive(Clone)]
 pub struct Chat {
     pub ratelimiters: Arc<Mutex<HashMap<Channel, RateLimiter>>>, // used to limit messages sent per channel
@@ -92,6 +95,52 @@ impl Chat {
             [ ] !! => 03.24 - Somewhere around here, we should be validating module for target channel
         */
 
+
+        /*
+            - Use ModulesManager.modstatus 
+
+            modstatus(&self, in_module: BotModule, in_chnl: Channel) -> StatusType 
+
+        */
+
+        let parent_module = params.get_parent_module().await;
+        // let parent_module = parent_module.clone();
+
+        let botlock = params.bot.read().await;
+        let modmgr = Arc::clone(&botlock.botmodules);
+        let modstatus = (*modmgr).modstatus(
+            parent_module.clone().expect("ERROR - Expected a module"), 
+            Channel(channel_login.clone())
+            ).await;
+
+        match modstatus {
+            super::botmodules::StatusType::Enabled(_) => (),
+            super::botmodules::StatusType::Disabled(_) => (),
+        }
+
+        if let super::botmodules::StatusType::Disabled(lvl) = modstatus {
+            // Note : At this point, chat was called in a channel where the parent module IS enabled
+            //  - this type of validation is done outside of Chat()
+            // This though takes into account scenarios where we are targetting a different channel
+
+            if let BotMsgType::SayInReplyTo(a, _) = msginput {
+                
+                self.say_in_reply_to(
+                    a, 
+                    format!("uuh {:?} is disabled on {} : {:?}",
+                            parent_module.clone().unwrap(),
+                            channel_login.clone(),
+                            lvl
+                         ), 
+                    params.clone()
+                ).await;
+
+
+            }
+
+            return
+            
+        }
         
 
         let rl = Arc::clone(&self.ratelimiters);
@@ -170,6 +219,7 @@ impl Chat {
 
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
+    #[async_recursion]
     pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
 
         self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;

From afd7b7d38705588b65b2d0af3f16a493e6eff60d Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 21:50:28 -0400
Subject: [PATCH 51/98] writelock_issue

---
 src/core/bot_actions.rs                  |  22 +-
 src/core/botinstance.rs                  |  11 +
 src/core/botmodules.rs                   |  13 +
 src/core/chat.rs                         | 301 +++++++++++++++++++++--
 src/custom/experimental/experiment002.rs |  12 +-
 5 files changed, 332 insertions(+), 27 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index d2d8d25..4b17758 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -6,7 +6,7 @@ use tokio::sync::RwLock;
 
 use crate::core::botinstance::BotInstance;
 
-use super::botmodules::{BotAction, BotModule};
+use super::{botmodules::{BotAction, BotModule}, identity::ChatBadge};
 
 
 pub type BotAR = Arc<RwLock<BotInstance>>;
@@ -41,6 +41,26 @@ impl ExecBodyParams {
         parent_module
     }
 
+    pub fn get_sender(&self) -> String {
+        self.msg.sender.name.clone()
+    }
+
+    pub fn get_sender_chatbadge(&self) -> Option<ChatBadge> {
+        
+        let mut requestor_badge_mut: Option<ChatBadge> = None;
+
+        for b in &self.msg.badges {
+            if b.name == "moderator" {
+                requestor_badge_mut = Some(ChatBadge::Mod);
+            } else if b.name == "broadcaster" {
+                requestor_badge_mut = Some(ChatBadge::Broadcaster);
+            }
+        }
+
+        let requestor_badge = requestor_badge_mut;
+
+        requestor_badge
+    }
 
 
 }
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index dc5e70b..b202e5b 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -390,6 +390,12 @@ impl BotInstance {
                                     Some(msg),
                                 );
 
+                                botlog::trace(
+                                    "ACQUIRING WRITE LOCK : ID",
+                                    Some("BotInstance > listener_main_prvmsg()".to_string()),
+                                    Some(msg),
+                                );
+
                                 
                                 const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
@@ -431,6 +437,11 @@ impl BotInstance {
                                 return;
                             };
 
+                            botlog::trace(
+                                "ACQUIRING WRITE LOCK : ID",
+                                Some("BotInstance > listener_main_prvmsg()".to_string()),
+                                Some(msg),
+                            );
 
 
                             let eval = {
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index b173e7b..5ae8ceb 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -846,6 +846,12 @@ impl ModulesManager {
             return ChangeResult::Failed("Module doesn't exist".to_string());
         }
 
+        botlog::trace(
+            "ACQUIRING WRITE LOCK : ID",
+            Some("ModulesManager > Exec_enable".to_string()),
+            None,
+        );
+
 
         let mut idlock = id.write().await;
 
@@ -1028,6 +1034,13 @@ impl ModulesManager {
             return ChangeResult::Failed("Module doesn't exist".to_string());
         }
 
+        botlog::trace(
+            "ACQUIRING WRITE LOCK : ID",
+            Some("ModulesManager > Exec_disable".to_string()),
+            None,
+        );
+
+
          
         let mut idlock = id.write().await;
 
diff --git a/src/core/chat.rs b/src/core/chat.rs
index a2d5b2b..2df41db 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -12,6 +12,7 @@ use casual_logger::Log;
 
 use rand::Rng;
 
+use crate::core::identity::Permissible;
 use crate::core::ratelimiter;
 use crate::core::ratelimiter::RateLimiter;
 
@@ -23,6 +24,7 @@ use tokio::time::{sleep, Duration};
 
 use super::bot_actions::ExecBodyParams;
 use super::botmodules::BotModule;
+use super::identity;
 
 
 use async_recursion::async_recursion;
@@ -34,7 +36,7 @@ pub struct Chat {
 }
 
 
-#[derive(Clone)]
+#[derive(Clone,Debug)]
 enum BotMsgType<'a> {
     SayInReplyTo(&'a PrivmsgMessage,String),
     Say(String,String),
@@ -71,6 +73,13 @@ impl Chat {
 
          */
 
+        
+        botlog::trace(
+            format!("send_bot_msg params : {:?}",msginput).as_str(),
+            Some("chat.rs > send_botmsg ".to_string()),
+            Some(&params.msg),
+        );
+
         let (channel_login,mut outmsg) = match msginput.clone() {
             BotMsgType::SayInReplyTo(msg, outmsg) => {
                 (msg.channel_login.clone(),outmsg)
@@ -80,7 +89,26 @@ impl Chat {
             },
         };
 
-        if self.client.get_channel_status(channel_login.clone()).await == (false,false) {
+
+        botlog::trace(
+            "BEFORE GET_CHANNEL_STATUS",
+        Some("chat.rs > send_botmsg ".to_string()),
+        Some(&params.msg),
+        );
+
+        let rslt = self.client.get_channel_status(channel_login.clone()).await == (false,false);
+        
+        botlog::trace(
+            format!("GET_CHANNEL_STATUS result = {:?}",rslt).as_str(),
+        Some("chat.rs > send_botmsg ".to_string()),
+        Some(&params.msg),
+        );
+
+        Log::flush();
+
+
+
+        if rslt {
             // in the case where the provided channel isn't something we're known to be connected to
 
             botlog::warn(
@@ -92,7 +120,7 @@ impl Chat {
         }
 
         /*
-            [ ] !! => 03.24 - Somewhere around here, we should be validating module for target channel
+            [x] !! => 03.24 - Somewhere around here, we should be validating module for target channel
         */
 
 
@@ -103,37 +131,105 @@ impl Chat {
 
         */
 
+                
+        botlog::trace(
+            "BEFORE parent_module call",
+        Some("chat.rs > send_botmsg ".to_string()),
+        Some(&params.msg),
+        );
+
         let parent_module = params.get_parent_module().await;
         // let parent_module = parent_module.clone();
 
-        let botlock = params.bot.read().await;
+        let params_clone = params.clone();
+        let botclone = Arc::clone(&params_clone.bot);
+        let botlock = botclone.read().await;
         let modmgr = Arc::clone(&botlock.botmodules);
         let modstatus = (*modmgr).modstatus(
             parent_module.clone().expect("ERROR - Expected a module"), 
             Channel(channel_login.clone())
             ).await;
 
-        match modstatus {
-            super::botmodules::StatusType::Enabled(_) => (),
-            super::botmodules::StatusType::Disabled(_) => (),
-        }
+        // match modstatus {
+        //     super::botmodules::StatusType::Enabled(_) => (),
+        //     super::botmodules::StatusType::Disabled(_) => (),
+        // }
+
+                        
+        botlog::trace(
+            format!("BEFORE modstatus check : modstatus = {:?}",modstatus).as_str(),
+        Some("chat.rs > send_botmsg ".to_string()),
+        Some(&params.msg),
+        );
+
+        
 
         if let super::botmodules::StatusType::Disabled(lvl) = modstatus {
             // Note : At this point, chat was called in a channel where the parent module IS enabled
             //  - this type of validation is done outside of Chat()
             // This though takes into account scenarios where we are targetting a different channel
 
+
+            botlog::trace(
+                "BEFORE msginput check",
+            Some("chat.rs > send_botmsg ".to_string()),
+            Some(&params.msg),
+            );
+            
+            Log::flush();
+
+
             if let BotMsgType::SayInReplyTo(a, _) = msginput {
+
+                botlog::trace(
+                        "BEFORE potential Async recursion",
+                    Some("chat.rs > send_botmsg ".to_string()),
+                    Some(&params.clone().msg),
+                );
                 
-                self.say_in_reply_to(
-                    a, 
-                    format!("uuh {:?} is disabled on {} : {:?}",
-                            parent_module.clone().unwrap(),
-                            channel_login.clone(),
-                            lvl
-                         ), 
-                    params.clone()
-                ).await;
+             Log::flush();
+
+                
+                // self.say_in_reply_to(
+                //     a, 
+                //     format!("uuh {:?} is disabled on {} : {:?}",
+                //             parent_module.clone().unwrap(),
+                //             channel_login.clone(),
+                //             lvl
+                //          ), 
+                //     params.clone()
+                // ).await;
+
+                let chat_clone = self.clone();
+
+                // tokio::spawn( async move {
+                //     // for _ in 0..5 {
+                //     //     println!(">> Innterroutine triggered!");
+                //     //     sleep(Duration::from_secs_f64(5.0)).await;
+                //     //     }
+
+                //     chat_clone.say_in_reply_to(
+                //     a, 
+                //     format!("uuh {:?} is disabled on {} : {:?}",
+                //             parent_module.clone().unwrap(),
+                //             channel_login.clone(),
+                //             lvl
+                //          ), 
+                //         params.clone()
+                //     ).await;   
+                //     }
+                // );
+
+
+                botlog::trace(
+                    "AFTER potential Async recursion",
+                Some("chat.rs > send_botmsg ".to_string()),
+                Some(&params.msg),
+                );
+
+                
+                Log::flush();
+
 
 
             }
@@ -141,6 +237,155 @@ impl Chat {
             return
             
         }
+
+        
+            /* 
+            
+                [ ] !! => 03.24 - Would be nice if around here , validate the user has at least some special roles in target channel
+                    - NOTE : If these need to be refined, they can be by the custom module developer at the parent calling function of say()
+                    - This just prevents Chat from being triggered in a channel where the sending chatter does not have any special roles
+
+            */
+
+            /*
+            
+            Use the following
+
+                pub async fn can_user_run(
+                    &mut self,
+                    usr: String,
+                    channelname: Channel,
+                    chat_badge: Option<ChatBadge>,
+                    cmdreqroles: Vec<UserRole>, // ) -> Result<Permissible,Box<dyn Error>> {
+                ) -> (Permissible, ChangeResult) {
+
+             */
+
+             botlog::trace(
+                "BEFORE Permissibility checks",
+            Some("chat.rs > send_botmsg ".to_string()),
+            Some(&params.msg),
+            );
+
+            Log::flush();
+    
+
+            const OF_CMD_CHANNEL:Channel = Channel(String::new());
+
+            let permissability = Permissible::Allow;
+
+            {
+
+                
+                // let id = botlock.get_identity();
+                // let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
+                let channel_login_clone = channel_login.clone();
+
+                
+                let spawnhandle = tokio::spawn( 
+                    async move {
+                        let botclone = Arc::clone(&params_clone.bot);
+                        let botlock = botclone.read().await;
+                        let id = botlock.get_identity();
+
+                        
+                        // botlog::trace(
+                        //     "ACQUIRING WRITE LOCK : ID",
+                        //     Some("Chat > send_botmsg".to_string()),
+                        //     Some(&params.msg),
+                        // );
+
+
+                        // {
+                        // let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
+                        // }
+
+                        // botlog::trace(
+                        //     "ACQUIRED WRITE LOCK : ID",
+                        //     Some("Chat > send_botmsg".to_string()),
+                        //     Some(&params.msg),
+                        // );
+
+                        // let (permissability, _) = idlock
+                        // .can_user_run(
+                        //     params.get_sender(),
+                        //     Channel(channel_login_clone),
+                        //     params.get_sender_chatbadge(),
+                        //                         vec![
+                        //         //identity::UserRole::BotAdmin,
+                        //         identity::UserRole::Mod(OF_CMD_CHANNEL),
+                        //         identity::UserRole::SupMod(OF_CMD_CHANNEL),
+                        //         identity::UserRole::Broadcaster,
+                        //     ]
+                        // ).await;
+                        // permissability
+                    }
+                );
+
+                if let Ok(permissibility) = spawnhandle.await {
+                    botlog::trace(
+                        format!("permisibility check : {:?}",permissability).as_str(),
+                    Some("chat.rs > send_botmsg ".to_string()),
+                    None
+                    );
+        
+                }
+
+
+            }
+
+
+    
+
+            // let permissability = {
+                // let id = botlock.get_identity();
+                // let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
+            //     let (permissability, _) = idlock
+            //         .can_user_run(
+            //             params.get_sender(),
+            //             Channel(channel_login.clone()),
+            //             params.get_sender_chatbadge(),
+            //                                 vec![
+            //                 //identity::UserRole::BotAdmin,
+            //                 identity::UserRole::Mod(OF_CMD_CHANNEL),
+            //                 identity::UserRole::SupMod(OF_CMD_CHANNEL),
+            //                 identity::UserRole::Broadcaster,
+            //             ]
+            //         ).await;
+            //     permissability
+            // };
+
+            // match permissability {
+            //     Permissible::Allow => (),
+            //     Permissible::Block => (),
+            // }
+
+            botlog::trace(
+                format!("permisibility check : {:?}",permissability).as_str(),
+            Some("chat.rs > send_botmsg ".to_string()),
+            None,
+            );
+
+            Log::flush();
+
+            if let Permissible::Block = permissability {
+
+
+                if let BotMsgType::SayInReplyTo(a, _) = msginput {
+                
+                    // self.say_in_reply_to(
+                    //     a, 
+                    //     format!("uuh you don't have special privileges in {}",
+                    //             channel_login.clone()
+                    //          ), 
+                    //     params.clone()
+                    // ).await;
+    
+                }
+                return
+
+            }
+
         
 
         let rl = Arc::clone(&self.ratelimiters);
@@ -222,6 +467,28 @@ impl Chat {
     #[async_recursion]
     pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
 
+        let botclone = Arc::clone(&params.bot);
+        let botlock = botclone.read().await;
+        let id = botlock.get_identity();
+
+        botlog::trace(
+            "ACQUIRING WRITE LOCK : ID",
+            Some("Chat > send_botmsg".to_string()),
+            Some(&params.msg),
+        );
+
+
+        {
+        let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
+        }
+
+        botlog::trace(
+            "ACQUIRED WRITE LOCK : ID",
+            Some("Chat > send_botmsg".to_string()),
+            Some(&params.msg),
+        );
+
+
         self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;
 
     }
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index be53ffa..d657c19 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -57,8 +57,11 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     botc1.add_to_modmgr(Arc::clone(&mgr)).await;
 
+    // If enabling by defauling at instance level
     mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await;
 
+    // [ ] #TODO - FOR SOME REASON, IF DISABLED BY DEFAULT, IT OVERFLOWS at RUNGTIME
+
 
 }
 
@@ -79,15 +82,6 @@ async fn sayout(params : ExecBodyParams) {
             [x] Get the parent module
         */
 
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
-
     let parent_module = params.get_parent_module().await;
 
 

From ab5624c6fa8fe2e6bc4778bd34ac7cbe17f68d75 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 22:55:38 -0400
Subject: [PATCH 52/98] (init) solution

---
 src/core/chat.rs | 47 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 38 insertions(+), 9 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index 2df41db..d596a68 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -464,29 +464,58 @@ impl Chat {
 
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
-    #[async_recursion]
+    // #[async_recursion]
     pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
 
-        let botclone = Arc::clone(&params.bot);
+        let params_clone = params.clone();
+
+        let botclone = Arc::clone(&params_clone.bot);
         let botlock = botclone.read().await;
         let id = botlock.get_identity();
+        let id = Arc::clone(&id);
+
+        // botlog::trace(
+        //     "ACQUIRING WRITE LOCK : ID",
+        //     Some("Chat > send_botmsg".to_string()),
+        //     Some(&params.msg),
+        // );
+        // Log::flush();
 
         botlog::trace(
-            "ACQUIRING WRITE LOCK : ID",
+            "ACQUIRING READ LOCK : ID",
             Some("Chat > send_botmsg".to_string()),
             Some(&params.msg),
         );
+        Log::flush();
 
-
-        {
-        let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
-        }
-
+        
+        // let idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
+        let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+        let a = idlock.getspecialuserroles(params.get_sender(), Some(Channel(msg.channel_login.clone()))).await;
         botlog::trace(
-            "ACQUIRED WRITE LOCK : ID",
+            format!("GETSPECIALUSERROLES RESULT : {:?}",a).as_str(),
             Some("Chat > send_botmsg".to_string()),
             Some(&params.msg),
         );
+        Log::flush();
+        
+        
+
+        // botlog::trace(
+        //     "ACQUIRED WRITE LOCK : ID",
+        //     Some("Chat > send_botmsg".to_string()),
+        //     Some(&params.msg),
+        // );
+        // Log::flush();
+
+
+        
+        botlog::trace(
+            "ACQUIRED READ LOCK : ID",
+            Some("Chat > send_botmsg".to_string()),
+            Some(&params.msg),
+        );
+        Log::flush();
 
 
         self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;

From cfadd730962f6372b3f7395d456e32db37eed1b5 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 23:27:21 -0400
Subject: [PATCH 53/98] readlock fix

---
 src/core/chat.rs | 116 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 83 insertions(+), 33 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index d596a68..4cfc027 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -247,6 +247,52 @@ impl Chat {
 
             */
 
+
+            /*
+            
+                Use 
+                pub async fn getspecialuserroles(
+                    &self,
+                    chattername: String,
+                    channel: Option<Channel>,
+                ) -> Vec<UserRole> {
+
+             */
+
+            //  let params_clone = params.clone();
+
+             let botclone = Arc::clone(&params.bot);
+             let botlock = botclone.read().await;
+             let id = botlock.get_identity();
+             let id = Arc::clone(&id);
+             let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+             let user_roles = idlock.getspecialuserroles(
+                params.get_sender(), 
+                Some(Channel(channel_login.clone()))
+            ).await;
+
+            // [ ] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send
+            // - Otherwise if not (checked here) , this will not run
+            // - NOTE : For now, I've removed BotAdmin just for curiosity - BotAdmins can always elevate themselves if they want
+
+            if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
+                || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
+                || user_roles.contains(&identity::UserRole::Broadcaster)) 
+            {
+
+
+                self.say_in_reply_to(
+                    &params.msg, 
+                    format!("uuh You do not have the right roles to send to {}",
+                            channel_login.clone(),
+                        ), 
+                    params.clone()
+                ).await;
+
+                return;
+
+            }
+
             /*
             
             Use the following
@@ -261,6 +307,8 @@ impl Chat {
 
              */
 
+            /*
+
              botlog::trace(
                 "BEFORE Permissibility checks",
             Some("chat.rs > send_botmsg ".to_string()),
@@ -360,6 +408,7 @@ impl Chat {
             //     Permissible::Block => (),
             // }
 
+
             botlog::trace(
                 format!("permisibility check : {:?}",permissability).as_str(),
             Some("chat.rs > send_botmsg ".to_string()),
@@ -387,6 +436,7 @@ impl Chat {
             }
 
         
+            */
 
         let rl = Arc::clone(&self.ratelimiters);
         let mut rllock = rl.lock().await;
@@ -464,58 +514,58 @@ impl Chat {
 
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
-    // #[async_recursion]
+    #[async_recursion]
     pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
 
-        let params_clone = params.clone();
+        // let params_clone = params.clone();
 
-        let botclone = Arc::clone(&params_clone.bot);
-        let botlock = botclone.read().await;
-        let id = botlock.get_identity();
-        let id = Arc::clone(&id);
+        // let botclone = Arc::clone(&params_clone.bot);
+        // let botlock = botclone.read().await;
+        // let id = botlock.get_identity();
+        // let id = Arc::clone(&id);
+
+        // // botlog::trace(
+        // //     "ACQUIRING WRITE LOCK : ID",
+        // //     Some("Chat > send_botmsg".to_string()),
+        // //     Some(&params.msg),
+        // // );
+        // // Log::flush();
 
         // botlog::trace(
-        //     "ACQUIRING WRITE LOCK : ID",
+        //     "ACQUIRING READ LOCK : ID",
         //     Some("Chat > send_botmsg".to_string()),
         //     Some(&params.msg),
         // );
         // Log::flush();
 
-        botlog::trace(
-            "ACQUIRING READ LOCK : ID",
-            Some("Chat > send_botmsg".to_string()),
-            Some(&params.msg),
-        );
-        Log::flush();
-
         
-        // let idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
-        let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
-        let a = idlock.getspecialuserroles(params.get_sender(), Some(Channel(msg.channel_login.clone()))).await;
-        botlog::trace(
-            format!("GETSPECIALUSERROLES RESULT : {:?}",a).as_str(),
-            Some("Chat > send_botmsg".to_string()),
-            Some(&params.msg),
-        );
-        Log::flush();
-        
-        
-
+        // // let idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
+        // let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+        // let a = idlock.getspecialuserroles(params.get_sender(), Some(Channel(msg.channel_login.clone()))).await;
         // botlog::trace(
-        //     "ACQUIRED WRITE LOCK : ID",
+        //     format!("GETSPECIALUSERROLES RESULT : {:?}",a).as_str(),
         //     Some("Chat > send_botmsg".to_string()),
         //     Some(&params.msg),
         // );
         // Log::flush();
+        
+        
+
+        // // botlog::trace(
+        // //     "ACQUIRED WRITE LOCK : ID",
+        // //     Some("Chat > send_botmsg".to_string()),
+        // //     Some(&params.msg),
+        // // );
+        // // Log::flush();
 
 
         
-        botlog::trace(
-            "ACQUIRED READ LOCK : ID",
-            Some("Chat > send_botmsg".to_string()),
-            Some(&params.msg),
-        );
-        Log::flush();
+        // botlog::trace(
+        //     "ACQUIRED READ LOCK : ID",
+        //     Some("Chat > send_botmsg".to_string()),
+        //     Some(&params.msg),
+        // );
+        // Log::flush();
 
 
         self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;

From 8b3395c19a26da918e70e14cfe00fb1d089cfc03 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Sun, 24 Mar 2024 23:42:59 -0400
Subject: [PATCH 54/98] smol

---
 src/core/chat.rs | 156 +++++++++++++++++++++++++++--------------------
 1 file changed, 89 insertions(+), 67 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index 4cfc027..2a6fc26 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -64,6 +64,9 @@ impl Chat {
 
     // async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
     async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
+
+        
+            
                 /*
         formats message before sending to TwitchIRC
 
@@ -74,7 +77,7 @@ impl Chat {
          */
 
         
-        botlog::trace(
+         botlog::trace(
             format!("send_bot_msg params : {:?}",msginput).as_str(),
             Some("chat.rs > send_botmsg ".to_string()),
             Some(&params.msg),
@@ -90,47 +93,7 @@ impl Chat {
         };
 
 
-        botlog::trace(
-            "BEFORE GET_CHANNEL_STATUS",
-        Some("chat.rs > send_botmsg ".to_string()),
-        Some(&params.msg),
-        );
-
-        let rslt = self.client.get_channel_status(channel_login.clone()).await == (false,false);
         
-        botlog::trace(
-            format!("GET_CHANNEL_STATUS result = {:?}",rslt).as_str(),
-        Some("chat.rs > send_botmsg ".to_string()),
-        Some(&params.msg),
-        );
-
-        Log::flush();
-
-
-
-        if rslt {
-            // in the case where the provided channel isn't something we're known to be connected to
-
-            botlog::warn(
-                &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
-                Some("Chat > send_botmsg".to_string()),
-                None,
-            );
-            return ;
-        }
-
-        /*
-            [x] !! => 03.24 - Somewhere around here, we should be validating module for target channel
-        */
-
-
-        /*
-            - Use ModulesManager.modstatus 
-
-            modstatus(&self, in_module: BotModule, in_chnl: Channel) -> StatusType 
-
-        */
-
                 
         botlog::trace(
             "BEFORE parent_module call",
@@ -150,6 +113,65 @@ impl Chat {
             Channel(channel_login.clone())
             ).await;
 
+
+        // botlog::trace(
+        //     "BEFORE GET_CHANNEL_STATUS",
+        // Some("chat.rs > send_botmsg ".to_string()),
+        // Some(&params.msg),
+        // );
+
+        // let rslt = self.client.get_channel_status(channel_login.clone()).await == (false,false);
+        
+        // botlog::trace(
+        //     format!("GET_CHANNEL_STATUS result = {:?}",rslt).as_str(),
+        // Some("chat.rs > send_botmsg ".to_string()),
+        // Some(&params.msg),
+        // );
+
+        // Log::flush();
+
+
+
+        // if rslt {
+        //     // in the case where the provided channel isn't something we're known to be connected to
+
+        //     botlog::warn(
+        //         &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
+        //         Some("Chat > send_botmsg".to_string()),
+        //         None,
+        //     );
+        //     return ;
+        // }
+
+        if !params.bot.read().await.bot_channels.contains(&Channel(channel_login.clone())) {
+            botlog::warn(
+                &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
+                Some("Chat > send_botmsg".to_string()),
+                None,
+            );
+
+            self.say_in_reply_to(
+                &params.msg, 
+                "uuh Bot can't send to a channel it isn't joined".to_string(), 
+                params.clone()
+            ).await;
+
+            return ;
+        }
+
+        /*
+            [x] !! => 03.24 - Somewhere around here, we should be validating module for target channel
+        */
+
+
+        /*
+            - Use ModulesManager.modstatus 
+
+            modstatus(&self, in_module: BotModule, in_chnl: Channel) -> StatusType 
+
+        */
+
+
         // match modstatus {
         //     super::botmodules::StatusType::Enabled(_) => (),
         //     super::botmodules::StatusType::Disabled(_) => (),
@@ -190,35 +212,35 @@ impl Chat {
              Log::flush();
 
                 
-                // self.say_in_reply_to(
-                //     a, 
-                //     format!("uuh {:?} is disabled on {} : {:?}",
-                //             parent_module.clone().unwrap(),
-                //             channel_login.clone(),
-                //             lvl
-                //          ), 
-                //     params.clone()
-                // ).await;
+                self.say_in_reply_to(
+                    a, 
+                    format!("uuh {:?} is disabled on {} : {:?}",
+                            parent_module.clone().unwrap(),
+                            channel_login.clone(),
+                            lvl
+                         ), 
+                    params.clone()
+                ).await;
 
-                let chat_clone = self.clone();
+                // let chat_clone = self.clone();
 
-                // tokio::spawn( async move {
-                //     // for _ in 0..5 {
-                //     //     println!(">> Innterroutine triggered!");
-                //     //     sleep(Duration::from_secs_f64(5.0)).await;
-                //     //     }
+                // // tokio::spawn( async move {
+                // //     // for _ in 0..5 {
+                // //     //     println!(">> Innterroutine triggered!");
+                // //     //     sleep(Duration::from_secs_f64(5.0)).await;
+                // //     //     }
 
-                //     chat_clone.say_in_reply_to(
-                //     a, 
-                //     format!("uuh {:?} is disabled on {} : {:?}",
-                //             parent_module.clone().unwrap(),
-                //             channel_login.clone(),
-                //             lvl
-                //          ), 
-                //         params.clone()
-                //     ).await;   
-                //     }
-                // );
+                // //     chat_clone.say_in_reply_to(
+                // //     a, 
+                // //     format!("uuh {:?} is disabled on {} : {:?}",
+                // //             parent_module.clone().unwrap(),
+                // //             channel_login.clone(),
+                // //             lvl
+                // //          ), 
+                // //         params.clone()
+                // //     ).await;   
+                // //     }
+                // // );
 
 
                 botlog::trace(

From 246c3d98e677ff70b888ca7ef08d933d5f8c9fa7 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 09:30:15 -0400
Subject: [PATCH 55/98] smol

---
 src/core/botinstance.rs                  | 98 ++++++++++++++++++------
 src/core/chat.rs                         | 72 +++++++++--------
 src/custom/experimental/experiment001.rs |  2 +-
 src/custom/experimental/experiment002.rs | 42 +++++-----
 4 files changed, 136 insertions(+), 78 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index b202e5b..750061c 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -390,40 +390,48 @@ impl BotInstance {
                                     Some(msg),
                                 );
 
+                                
+                                let botclone = Arc::clone(&bot);
+                                let botlock = botclone.read().await;
+                                let id = botlock.get_identity();
+                                let id = Arc::clone(&id);
+                                let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+                                let user_roles = idlock.getspecialuserroles(
+                                    msg.sender.name.clone(), 
+                                    Some(Channel(msg.channel_login.clone()))
+                                ).await;
+
+
                                 botlog::trace(
-                                    "ACQUIRING WRITE LOCK : ID",
+                                    &format!("For Disabled Command Evaluating User Roles {:?}", user_roles),
                                     Some("BotInstance > listener_main_prvmsg()".to_string()),
                                     Some(msg),
                                 );
 
-                                
-                                const OF_CMD_CHANNEL:Channel = Channel(String::new());
+                                // Only respond to those with th ebelow User Roles
 
-                                let elevated_access = {
-                                    let mut idlock = id.write().await;
-                                    let (permissability, _) = idlock
-                                        .can_user_run_prvmsg(msg, 
-                                            vec![
-                                                identity::UserRole::BotAdmin,
-                                                identity::UserRole::Mod(OF_CMD_CHANNEL),
-                                                identity::UserRole::SupMod(OF_CMD_CHANNEL),
-                                                identity::UserRole::Broadcaster,
-                                            ])
-                                        .await;
-    
-                                    permissability
-                                };
-
-                                if let Permissible::Allow = elevated_access {
-                                    let botlock = bot.read().await;
+                                if user_roles.contains(&identity::UserRole::Mod(Channel(msg.channel_login.clone()))) 
+                                || user_roles.contains(&identity::UserRole::SupMod(Channel(msg.channel_login.clone()))) 
+                                || user_roles.contains(&identity::UserRole::Broadcaster)
+                                || user_roles.contains(&identity::UserRole::BotAdmin) 
+                                {
+                    
+                    
+                                    // self.say_in_reply_to(
+                                    //     &params.msg, 
+                                    //     format!("uuh You do not have the right roles to send to {}",
+                                    //             channel_login.clone(),
+                                    //         ), 
+                                    //     params.clone()
+                                    // ).await;
                                     let outstr =
                                         format!("sadg Module is disabled : {:?}",a);
 
+                                    
                                     let params = ExecBodyParams {
                                         bot : Arc::clone(&bot),
                                         msg : (*msg).clone(),
                                         parent_act : Arc::clone(&act_clone),
-
                                     };
 
                                     botlock.botmgrs.chat.say_in_reply_to(
@@ -432,7 +440,53 @@ impl BotInstance {
                                         // c.module.clone()
                                         params,
                                     ).await;
-                                } 
+                    
+                                }
+
+
+                                // botlog::trace(
+                                //     "ACQUIRING WRITE LOCK : ID",
+                                //     Some("BotInstance > listener_main_prvmsg()".to_string()),
+                                //     Some(msg),
+                                // );
+
+                                
+                                // const OF_CMD_CHANNEL:Channel = Channel(String::new());
+
+                                // let elevated_access = {
+                                //     let mut idlock = id.write().await;
+                                //     let (permissability, _) = idlock
+                                //         .can_user_run_prvmsg(msg, 
+                                //             vec![
+                                //                 identity::UserRole::BotAdmin,
+                                //                 identity::UserRole::Mod(OF_CMD_CHANNEL),
+                                //                 identity::UserRole::SupMod(OF_CMD_CHANNEL),
+                                //                 identity::UserRole::Broadcaster,
+                                //             ])
+                                //         .await;
+    
+                                //     permissability
+                                // };
+
+                                // if let Permissible::Allow = elevated_access {
+                                //     let botlock = bot.read().await;
+                                //     let outstr =
+                                //         format!("sadg Module is disabled : {:?}",a);
+
+                                //     let params = ExecBodyParams {
+                                //         bot : Arc::clone(&bot),
+                                //         msg : (*msg).clone(),
+                                //         parent_act : Arc::clone(&act_clone),
+
+                                //     };
+
+                                //     botlock.botmgrs.chat.say_in_reply_to(
+                                //         msg, 
+                                //         outstr,
+                                //         // c.module.clone()
+                                //         params,
+                                //     ).await;
+                                // } 
 
                                 return;
                             };
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 2a6fc26..6fc546a 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -82,6 +82,7 @@ impl Chat {
             Some("chat.rs > send_botmsg ".to_string()),
             Some(&params.msg),
         );
+        Log::flush();
 
         let (channel_login,mut outmsg) = match msginput.clone() {
             BotMsgType::SayInReplyTo(msg, outmsg) => {
@@ -150,12 +151,20 @@ impl Chat {
                 None,
             );
 
-            self.say_in_reply_to(
-                &params.msg, 
-                "uuh Bot can't send to a channel it isn't joined".to_string(), 
-                params.clone()
-            ).await;
+            // self.say_in_reply_to(
+            //     &params.msg, 
+            //     "uuh Bot can't send to a channel it isn't joined".to_string(), 
+            //     params.clone()
+            // ).await;
+            if let BotMsgType::SayInReplyTo(a,_) = msginput {
 
+                self.say_in_reply_to(
+                    a, 
+                    "uuh Bot can't send to a channel it isn't joined".to_string(), 
+                    params.clone()
+                ).await;
+
+            }
             return ;
         }
 
@@ -222,26 +231,6 @@ impl Chat {
                     params.clone()
                 ).await;
 
-                // let chat_clone = self.clone();
-
-                // // tokio::spawn( async move {
-                // //     // for _ in 0..5 {
-                // //     //     println!(">> Innterroutine triggered!");
-                // //     //     sleep(Duration::from_secs_f64(5.0)).await;
-                // //     //     }
-
-                // //     chat_clone.say_in_reply_to(
-                // //     a, 
-                // //     format!("uuh {:?} is disabled on {} : {:?}",
-                // //             parent_module.clone().unwrap(),
-                // //             channel_login.clone(),
-                // //             lvl
-                // //          ), 
-                // //         params.clone()
-                // //     ).await;   
-                // //     }
-                // // );
-
 
                 botlog::trace(
                     "AFTER potential Async recursion",
@@ -269,6 +258,9 @@ impl Chat {
 
             */
 
+            
+
+
 
             /*
             
@@ -293,23 +285,35 @@ impl Chat {
                 Some(Channel(channel_login.clone()))
             ).await;
 
+            botlog::trace(
+                format!("BEFORE user roles check check : userroles = {:?}",user_roles).as_str(),
+            Some("chat.rs > send_botmsg ".to_string()),
+            Some(&params.msg),
+            );
+
+            Log::flush();
+
             // [ ] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send
             // - Otherwise if not (checked here) , this will not run
             // - NOTE : For now, I've removed BotAdmin just for curiosity - BotAdmins can always elevate themselves if they want
 
+            // if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
+            //     || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
+            //     || user_roles.contains(&identity::UserRole::Broadcaster)) 
             if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
-                || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
-                || user_roles.contains(&identity::UserRole::Broadcaster)) 
+            || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
+            || user_roles.contains(&identity::UserRole::Broadcaster)
+            || user_roles.contains(&identity::UserRole::BotAdmin)) 
             {
 
 
-                self.say_in_reply_to(
-                    &params.msg, 
-                    format!("uuh You do not have the right roles to send to {}",
-                            channel_login.clone(),
-                        ), 
-                    params.clone()
-                ).await;
+                // self.say_in_reply_to(
+                //     &params.msg, 
+                //     format!("uuh You do not have the right roles to send to {}",
+                //             channel_login.clone(),
+                //         ), 
+                //     params.clone()
+                // ).await;
 
                 return;
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 54e6552..be0cb8d 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -142,7 +142,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
-        let rollwin = rand::thread_rng().gen_ratio(1, 1);
+        let rollwin = rand::thread_rng().gen_ratio(1, 10);
 
         if rollwin {
             botlog::debug(
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index d657c19..96c92c5 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -145,34 +145,34 @@ async fn sayout(params : ExecBodyParams) {
                 None,
             );
 
-            // if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
-            if !botlock.bot_channels.contains(&Channel(trgchnl.to_lowercase().to_string().clone())) {
+            // // if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
+            // if !botlock.bot_channels.contains(&Channel(trgchnl.to_lowercase().to_string().clone())) {
 
-                // in the case where the provided channel isn't something we're known to be connected to
-                botlog::warn(
-                    &format!("A message attempted to send for a Non-Joined Channel : {}",trgchnl.to_string().clone()),
-                    Some("Chat > send_botmsg".to_string()),
-                    None,
-                );
-                // return ;
+            //     // in the case where the provided channel isn't something we're known to be connected to
+            //     botlog::warn(
+            //         &format!("A message attempted to send for a Non-Joined Channel : {}",trgchnl.to_string().clone()),
+            //         Some("Chat > send_botmsg".to_string()),
+            //         None,
+            //     );
+            //     // return ;
 
-                if parent_module.clone().is_some() {
+            //     if parent_module.clone().is_some() {
 
                     
-                    botlock
-                    .botmgrs
-                    .chat
-                    .say_in_reply_to(
-                        &params.msg, 
-                        format!("Not a Joined Channel : {}",trgchnl),
-                        // parent_module.clone().unwrap().clone()
-                        params.clone(),
-                    ).await;
+            //         botlock
+            //         .botmgrs
+            //         .chat
+            //         .say_in_reply_to(
+            //             &params.msg, 
+            //             format!("Not a Joined Channel : {}",trgchnl),
+            //             // parent_module.clone().unwrap().clone()
+            //             params.clone(),
+            //         ).await;
 
-                }
+            //     }
 
 
-            }
+            // }
 
             /*
                 1. If a Reply , 

From 10d25bf34f9ca66cac3e4c68593f429f0b1609d7 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 10:07:34 -0400
Subject: [PATCH 56/98] notif BotMsgType

---
 src/core/chat.rs | 125 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 85 insertions(+), 40 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index 6fc546a..e82fd0a 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -40,6 +40,7 @@ pub struct Chat {
 enum BotMsgType<'a> {
     SayInReplyTo(&'a PrivmsgMessage,String),
     Say(String,String),
+    Notif(String), // For Bot Sent Notifications
 }
 
 
@@ -63,7 +64,9 @@ impl Chat {
 
 
     // async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
-    async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
+    #[async_recursion]
+    // async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
+    async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
 
         
             
@@ -91,6 +94,10 @@ impl Chat {
             BotMsgType::Say(a,b ) => {
                 (a.clone(),b.clone())
             },
+            BotMsgType::Notif(outmsg) => {
+                // (msg.channel_login.clone(),outmsg)
+                (params.msg.channel_login.clone(),outmsg)
+            }
         };
 
 
@@ -156,15 +163,20 @@ impl Chat {
             //     "uuh Bot can't send to a channel it isn't joined".to_string(), 
             //     params.clone()
             // ).await;
-            if let BotMsgType::SayInReplyTo(a,_) = msginput {
+            if let BotMsgType::SayInReplyTo(_prvmsg,_outmsg) = msginput {
 
-                self.say_in_reply_to(
-                    a, 
+                // self.say_in_reply_to(
+                //     a, 
+                //     "uuh Bot can't send to a channel it isn't joined".to_string(), 
+                //     params.clone()
+                // ).await;
+                self.send_botmsg(BotMsgType::Notif(
                     "uuh Bot can't send to a channel it isn't joined".to_string(), 
-                    params.clone()
-                ).await;
+                ), 
+                params).await;
 
             }
+
             return ;
         }
 
@@ -209,43 +221,42 @@ impl Chat {
             
             Log::flush();
 
+            match msginput {
+                BotMsgType::Notif(_) => (), // Do nothing with Notif > We'll validate the user later to handle
+                BotMsgType::SayInReplyTo(_, _) | BotMsgType::Say(_,_) => {
+                            
+                        botlog::trace(
+                            "BEFORE potential Async recursion",
+                        Some("chat.rs > send_botmsg ".to_string()),
+                        Some(&params.clone().msg),
+                    );
+                        
+                    Log::flush();
 
-            if let BotMsgType::SayInReplyTo(a, _) = msginput {
 
-                botlog::trace(
-                        "BEFORE potential Async recursion",
+                    self.send_botmsg(BotMsgType::Notif(
+                        format!("uuh {:?} is disabled on {} : {:?}",
+                                parent_module.clone().unwrap(),
+                                channel_login.clone(),
+                                lvl
+                            ),                     
+                        ), params.clone()
+                    ).await;
+
+
+                    botlog::trace(
+                        "AFTER potential Async recursion",
                     Some("chat.rs > send_botmsg ".to_string()),
-                    Some(&params.clone().msg),
-                );
+                    Some(&params.msg),
+                    );
+
+                    
+                    Log::flush();
+
+                    return 
+                },
                 
-             Log::flush();
-
-                
-                self.say_in_reply_to(
-                    a, 
-                    format!("uuh {:?} is disabled on {} : {:?}",
-                            parent_module.clone().unwrap(),
-                            channel_login.clone(),
-                            lvl
-                         ), 
-                    params.clone()
-                ).await;
-
-
-                botlog::trace(
-                    "AFTER potential Async recursion",
-                Some("chat.rs > send_botmsg ".to_string()),
-                Some(&params.msg),
-                );
-
-                
-                Log::flush();
-
-
-
             }
-
-            return
             
         }
 
@@ -315,10 +326,41 @@ impl Chat {
                 //     params.clone()
                 // ).await;
 
-                return;
+                match msginput {
+                    BotMsgType::Notif(_) => {
+                        // If the BotMsg is an Error Notification , and the Sender does not have Specific Roles in the Source Channel Sent (where the Error Notif will be sent)
+                        return // return in this case - the User should not see a notification if this path is reached
+                    },
+                    BotMsgType::SayInReplyTo(_,_ ) | BotMsgType::Say(_,_) => {
+                        // If the BotMsg a Say/SayInReplyTo (from Developer or Chatter) , and the Sender does not have Specific Roles in the Source Channel Sent
+
+                        self.send_botmsg(BotMsgType::Notif(
+                            format!("uuh You do not have the right roles to send to {}",
+                                    channel_login.clone(),
+                                ),                    
+                            ), params.clone()
+                        ).await;
+        
+                        return;
+
+                    },
+                };
+
+
 
             }
 
+
+            /*
+                At this stage from the above Validations : 
+                msginput would be : 
+                    a. BotMsgType::SayInReplyTo | BotMsgType::Say that is 
+                        - Towards a Destination Channel that the Sender has Elevated User Roles to Send to
+                    b. BotMsgType::Notif that is 
+                        - Going to be sent to the Source Channel (rather than the original say/sayinreplyto was towards)
+                        - A Sender that has Elevated User Roles in Source Channel will see a message ; otherwise, they will not
+             */ 
+
             /*
             
             Use the following
@@ -499,6 +541,9 @@ impl Chat {
                     BotMsgType::Say(a, _) => {
                         self.client.say(a, outmsg).await.unwrap();
                     }
+                    BotMsgType::Notif(outmsg) => {
+                        self.client.say_in_reply_to(&params.msg, outmsg).await.unwrap();
+                    }
                 }
                 
                 contextratelimiter.increment_counter();
@@ -540,7 +585,7 @@ impl Chat {
 
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
-    #[async_recursion]
+    // #[async_recursion]
     pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
 
         // let params_clone = params.clone();

From c0603739c91ab03a0fe8ce9aa310c70d172ddc89 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 11:55:16 -0400
Subject: [PATCH 57/98] Notifs only sent for BotAdmins

---
 src/core/chat.rs | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index e82fd0a..c36fcf7 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -311,10 +311,15 @@ impl Chat {
             // if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
             //     || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
             //     || user_roles.contains(&identity::UserRole::Broadcaster)) 
+            // if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
+            // || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
+            // || user_roles.contains(&identity::UserRole::Broadcaster)
+            // || user_roles.contains(&identity::UserRole::BotAdmin)) 
+
             if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
             || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
             || user_roles.contains(&identity::UserRole::Broadcaster)
-            || user_roles.contains(&identity::UserRole::BotAdmin)) 
+            ) 
             {
 
 
@@ -328,8 +333,10 @@ impl Chat {
 
                 match msginput {
                     BotMsgType::Notif(_) => {
-                        // If the BotMsg is an Error Notification , and the Sender does not have Specific Roles in the Source Channel Sent (where the Error Notif will be sent)
-                        return // return in this case - the User should not see a notification if this path is reached
+                        // If Sender is Not a BotAdmin, don't do anything about the notification and return
+                        if !user_roles.contains(&identity::UserRole::BotAdmin) {
+                            return;
+                        }
                     },
                     BotMsgType::SayInReplyTo(_,_ ) | BotMsgType::Say(_,_) => {
                         // If the BotMsg a Say/SayInReplyTo (from Developer or Chatter) , and the Sender does not have Specific Roles in the Source Channel Sent

From 628db3c229ff3faa897fd7bb59b14e564c4a837d Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 14:11:21 -0400
Subject: [PATCH 58/98] refactor core to use Notif msg

---
 src/core/botinstance.rs |  71 ++++++++++++-------
 src/core/botmodules.rs  | 148 ++++++++++++++++++++++++++--------------
 src/core/chat.rs        |   4 +-
 src/core/identity.rs    |  63 ++++++++++-------
 4 files changed, 184 insertions(+), 102 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 750061c..ce55ff9 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -410,38 +410,57 @@ impl BotInstance {
 
                                 // Only respond to those with th ebelow User Roles
 
-                                if user_roles.contains(&identity::UserRole::Mod(Channel(msg.channel_login.clone()))) 
-                                || user_roles.contains(&identity::UserRole::SupMod(Channel(msg.channel_login.clone()))) 
-                                || user_roles.contains(&identity::UserRole::Broadcaster)
-                                || user_roles.contains(&identity::UserRole::BotAdmin) 
-                                {
+                                let outstr =
+                                format!("sadg Module is disabled : {:?}",a);
+
+                            
+                                let params = ExecBodyParams {
+                                    bot : Arc::clone(&bot),
+                                    msg : (*msg).clone(),
+                                    parent_act : Arc::clone(&act_clone),
+                                };
+
+                                // When sending a BotMsgTypeNotif, send_botmsg does Roles related validation as required
+
+                                botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                                    outstr
+                                    ),
+                                params,
+                                ).await;
+
+
+                                // if user_roles.contains(&identity::UserRole::Mod(Channel(msg.channel_login.clone()))) 
+                                // || user_roles.contains(&identity::UserRole::SupMod(Channel(msg.channel_login.clone()))) 
+                                // || user_roles.contains(&identity::UserRole::Broadcaster)
+                                // || user_roles.contains(&identity::UserRole::BotAdmin) 
+                                // {
                     
                     
-                                    // self.say_in_reply_to(
-                                    //     &params.msg, 
-                                    //     format!("uuh You do not have the right roles to send to {}",
-                                    //             channel_login.clone(),
-                                    //         ), 
-                                    //     params.clone()
-                                    // ).await;
-                                    let outstr =
-                                        format!("sadg Module is disabled : {:?}",a);
+                                //     // self.say_in_reply_to(
+                                //     //     &params.msg, 
+                                //     //     format!("uuh You do not have the right roles to send to {}",
+                                //     //             channel_login.clone(),
+                                //     //         ), 
+                                //     //     params.clone()
+                                //     // ).await;
+                                //     let outstr =
+                                //         format!("sadg Module is disabled : {:?}",a);
 
                                     
-                                    let params = ExecBodyParams {
-                                        bot : Arc::clone(&bot),
-                                        msg : (*msg).clone(),
-                                        parent_act : Arc::clone(&act_clone),
-                                    };
+                                //     let params = ExecBodyParams {
+                                //         bot : Arc::clone(&bot),
+                                //         msg : (*msg).clone(),
+                                //         parent_act : Arc::clone(&act_clone),
+                                //     };
 
-                                    botlock.botmgrs.chat.say_in_reply_to(
-                                        msg, 
-                                        outstr,
-                                        // c.module.clone()
-                                        params,
-                                    ).await;
+                                //     botlock.botmgrs.chat.say_in_reply_to(
+                                //         msg, 
+                                //         outstr,
+                                //         // c.module.clone()
+                                //         params,
+                                //     ).await;
                     
-                                }
+                                // }
 
 
                                 // botlog::trace(
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 5ae8ceb..6fded1b 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -117,9 +117,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         //      BotAction::C(c) => Some(&(*c).module),
         //      BotAction::L(l) => Some(&(*l).module),
         //      _ => None,
-        //  };
+        // //  };
 
-        let parent_module = params.get_parent_module().await;
+        // let parent_module = params.get_parent_module().await;
 
 
 
@@ -191,20 +191,42 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 Some(&params.msg),
             );
 
-            // Only call Say if there is a parent module passed
-            if parent_module.is_some() {
+            // We should call a notification around here
+
+            let bot = params.clone().bot;
+
+            let botclone = Arc::clone(&bot);
+            let botlock = botclone.read().await;
+            let id = botlock.get_identity();
+            let id = Arc::clone(&id);
+            let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+            let user_roles = idlock.getspecialuserroles(
+                params.msg.sender.name.clone(), 
+                Some(Channel(params.msg.channel_login.clone()))
+            ).await;
+
+            botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                outmsg.to_string()
+                ),
+            params.clone(),
+            ).await;
+
+
+
+            // // Only call Say if there is a parent module passed
+            // if parent_module.is_some() {
 
         
-                botlock
-                    .botmgrs
-                    .chat
-                    .say_in_reply_to(
-                        &params.msg, 
-                        outmsg.to_string() , 
-                        // parent_module.unwrap().clone()
-                        params.clone(),
-                    ).await;
-            }
+            //     botlock
+            //         .botmgrs
+            //         .chat
+            //         .say_in_reply_to(
+            //             &params.msg, 
+            //             outmsg.to_string() , 
+            //             // parent_module.unwrap().clone()
+            //             params.clone(),
+            //         ).await;
+            // }
 
             return;
 
@@ -236,6 +258,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             trg_level, 
             id).await;
 
+            
+        // We should call a notification around here
+
 
         let outmsg = match rslt.clone() {
             ChangeResult::Failed(a) => format!("Stare Failed : {}",a),
@@ -243,22 +268,30 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             ChangeResult::Success(a) => format!("YAAY Success : {}",a),
         };
 
+        botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+            outmsg.to_string()
+            ),
+        params.clone(),
+        ).await;
+
         
-            // Only call Say if there is a parent module passed
-            if parent_module.is_some() {
+
+        
+        // // Only call Say if there is a parent module passed
+        // if parent_module.is_some() {
 
 
-                botlock
-                    .botmgrs
-                    .chat
-                    .say_in_reply_to(
-                        &params.msg, 
-                        outmsg.to_string(),
-                        // parent_module.unwrap().clone()
-                        params.clone(),
-                    ).await;
+        //     botlock
+        //         .botmgrs
+        //         .chat
+        //         .say_in_reply_to(
+        //             &params.msg, 
+        //             outmsg.to_string(),
+        //             // parent_module.unwrap().clone()
+        //             params.clone(),
+        //         ).await;
 
-            }
+        // }
 
 
 
@@ -414,22 +447,29 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             //     _ => None,
             // };
 
+            // We should call a notification around here
+
+            botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                outmsg.to_string()
+                ),
+            params.clone(),
+            ).await;
 
 
-            // Only call Say if there is a parent module passed
-            if parent_module.is_some() {
+            // // Only call Say if there is a parent module passed
+            // if parent_module.is_some() {
 
-                botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(
-                    &params.msg, 
-                    outmsg.to_string(),
-                    // ,parent_module.unwrap().clone()
-                    params.clone()
-                ).await;
+            //     botlock
+            //     .botmgrs
+            //     .chat
+            //     .say_in_reply_to(
+            //         &params.msg, 
+            //         outmsg.to_string(),
+            //         // ,parent_module.unwrap().clone()
+            //         params.clone()
+            //     ).await;
 
-            }
+            // }
 
             return;
 
@@ -471,21 +511,29 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             ChangeResult::Success(a) => format!("YAAY Success : {}",a),
         };
 
+        // We should call a notification around here
 
-        // Only call Say if there is a parent module passed
-        if parent_module.is_some() {
+        botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+            outmsg.to_string()
+            ),
+        params.clone(),
+        ).await;
 
-            botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(
-                    &params.msg,
-                     outmsg.to_string(),
-                    //  parent_module.unwrap().clone()
-                    params.clone(),
-                ).await;
 
-        }
+        // // Only call Say if there is a parent module passed
+        // if parent_module.is_some() {
+
+        //     botlock
+        //         .botmgrs
+        //         .chat
+        //         .say_in_reply_to(
+        //             &params.msg,
+        //              outmsg.to_string(),
+        //             //  parent_module.unwrap().clone()
+        //             params.clone(),
+        //         ).await;
+
+        // }
     
 
 
diff --git a/src/core/chat.rs b/src/core/chat.rs
index c36fcf7..f07eb55 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -37,7 +37,7 @@ pub struct Chat {
 
 
 #[derive(Clone,Debug)]
-enum BotMsgType<'a> {
+pub enum BotMsgType<'a> {
     SayInReplyTo(&'a PrivmsgMessage,String),
     Say(String,String),
     Notif(String), // For Bot Sent Notifications
@@ -66,7 +66,7 @@ impl Chat {
     // async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
     #[async_recursion]
     // async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
-    async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
+    pub async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
 
         
             
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 0be4dea..b9223bf 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -231,21 +231,30 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
-        // Only call Say if there is a parent module passed
-        if parent_module.is_some() {
+        // We should call a notification around here
+
+        botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+            outmsg.to_string()
+            ),
+        params.clone(),
+        ).await;
 
 
-            botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(
-                        &params.msg, 
-                        outmsg.to_string(),
-                        // parent_module.unwrap().clone()
-                        params.clone(),
-                ).await;
+        // // Only call Say if there is a parent module passed
+        // if parent_module.is_some() {
 
-        }
+
+        //     botlock
+        //         .botmgrs
+        //         .chat
+        //         .say_in_reply_to(
+        //                 &params.msg, 
+        //                 outmsg.to_string(),
+        //                 // parent_module.unwrap().clone()
+        //                 params.clone(),
+        //         ).await;
+
+        // }
 
         botlog::trace(
             // &format!("End of cmd_promote()"),
@@ -458,21 +467,27 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
+        botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+            outmsg.to_string()
+            ),
+        params.clone(),
+        ).await;
 
-        // Only call Say if there is a parent module passed
-        if parent_module.is_some() {
 
-            botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(
-                    &params.msg, 
-                outmsg.to_string(),
-                    // parent_module.unwrap().clone()
-                    params.clone()
-                ).await;
+        // // Only call Say if there is a parent module passed
+        // if parent_module.is_some() {
 
-        }
+        //     botlock
+        //         .botmgrs
+        //         .chat
+        //         .say_in_reply_to(
+        //             &params.msg, 
+        //         outmsg.to_string(),
+        //             // parent_module.unwrap().clone()
+        //             params.clone()
+        //         ).await;
+
+        // }
 
 
 

From d746d0d073c82f7776aa6eaef46848f5c945a921 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 14:15:14 -0400
Subject: [PATCH 59/98] custom does not req parent_module validation before say

---
 src/core/identity.rs                     |  22 ++--
 src/custom/experimental/experiment001.rs | 131 ++++++++++++++++-------
 src/custom/experimental/experiment002.rs |  35 +++---
 3 files changed, 127 insertions(+), 61 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index b9223bf..756a50d 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -653,16 +653,22 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             Some(&params.msg),
         );
 
-        if parent_module.is_some() {
+        botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+            outmsg.to_string()
+            ),
+        params.clone(),
+        ).await;
 
-            botlock.botmgrs.chat.say_in_reply_to(
-                &params.msg, 
-                outmsg,
-                // parent_module.unwrap().clone()
-                params.clone()
-            ).await;
+        // if parent_module.is_some() {
 
-        }
+        //     botlock.botmgrs.chat.say_in_reply_to(
+        //         &params.msg, 
+        //         outmsg,
+        //         // parent_module.unwrap().clone()
+        //         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
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index be0cb8d..aa9575a 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -126,7 +126,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // };
 
     
-    let parent_module = params.get_parent_module().await;
+    // let parent_module = params.get_parent_module().await;
 
     // [ ] Uses gen_ratio() to output bool based on a ratio probability .
     //   - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator)
@@ -153,23 +153,34 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let bot = Arc::clone(&params.bot);
 
+
             let botlock = bot.read().await;
 
+            // uses chat.say_in_reply_to() for the bot controls for messages
+            botlock
+            .botmgrs
+            .chat
+            .say_in_reply_to(
+                &params.msg, 
+                String::from("GoodGirl xdd "),
+                // parent_module.unwrap().clone()
+                params.clone()
+            ).await;
 
-            if parent_module.is_some() {
+            // if parent_module.is_some() {
 
-                // uses chat.say_in_reply_to() for the bot controls for messages
-                botlock
-                    .botmgrs
-                    .chat
-                    .say_in_reply_to(
-                        &params.msg, 
-                        String::from("GoodGirl xdd "),
-                        // parent_module.unwrap().clone()
-                        params.clone()
-                    ).await;
+            //     // uses chat.say_in_reply_to() for the bot controls for messages
+            //     botlock
+            //         .botmgrs
+            //         .chat
+            //         .say_in_reply_to(
+            //             &params.msg, 
+            //             String::from("GoodGirl xdd "),
+            //             // parent_module.unwrap().clone()
+            //             params.clone()
+            //         ).await;
 
-            }
+            // }
 
         }
     }
@@ -219,46 +230,84 @@ async fn babygirl(params : ExecBodyParams) {
 
     let botlock = bot.read().await;
 
-    if parent_module.is_some() {
-
-        // uses chat.say_in_reply_to() for the bot controls for messages
-        botlock
-            .botmgrs
-            .chat
-            .say_in_reply_to(
-                &params.msg, 
-                String::from("16:13 notohh: cafdk"),
-                // parent_module.clone().unwrap().clone()
-                params.clone()
-            ).await;
 
 
-        sleep(Duration::from_secs_f64(0.5)).await;
-
-        botlock
+    // uses chat.say_in_reply_to() for the bot controls for messages
+    botlock
         .botmgrs
         .chat
         .say_in_reply_to(
             &params.msg, 
-            String::from("16:13 notohh: have fun eating princess"),
-            // parent_module.clone().unwrap().clone()
+            String::from("16:13 notohh: cafdk"),
             params.clone()
         ).await;
 
 
-        sleep(Duration::from_secs_f64(2.0)).await;
+    sleep(Duration::from_secs_f64(0.5)).await;
 
-        botlock
-        .botmgrs
-        .chat
-        .say_in_reply_to(
-            &params.msg, 
-            String::from("16:13 notohh: baby girl"),
-            // parent_module.unwrap().clone()
-            params.clone()
-        ).await;
+    botlock
+    .botmgrs
+    .chat
+    .say_in_reply_to(
+        &params.msg, 
+        String::from("16:13 notohh: have fun eating princess"),
+        params.clone()
+    ).await;
 
-    }
+
+    sleep(Duration::from_secs_f64(2.0)).await;
+
+    botlock
+    .botmgrs
+    .chat
+    .say_in_reply_to(
+        &params.msg, 
+        String::from("16:13 notohh: baby girl"),
+        params.clone()
+    ).await;
+
+
+
+    // if parent_module.is_some() {
+
+    //     // uses chat.say_in_reply_to() for the bot controls for messages
+    //     botlock
+    //         .botmgrs
+    //         .chat
+    //         .say_in_reply_to(
+    //             &params.msg, 
+    //             String::from("16:13 notohh: cafdk"),
+    //             // parent_module.clone().unwrap().clone()
+    //             params.clone()
+    //         ).await;
+
+
+    //     sleep(Duration::from_secs_f64(0.5)).await;
+
+    //     botlock
+    //     .botmgrs
+    //     .chat
+    //     .say_in_reply_to(
+    //         &params.msg, 
+    //         String::from("16:13 notohh: have fun eating princess"),
+    //         // parent_module.clone().unwrap().clone()
+    //         params.clone()
+    //     ).await;
+
+
+    //     sleep(Duration::from_secs_f64(2.0)).await;
+
+    //     botlock
+    //     .botmgrs
+    //     .chat
+    //     .say_in_reply_to(
+    //         &params.msg, 
+    //         String::from("16:13 notohh: baby girl"),
+    //         // parent_module.unwrap().clone()
+    //         params.clone()
+    //     ).await;
+
+    // }
 
 
 }
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 96c92c5..fa4a6ce 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -250,21 +250,32 @@ async fn sayout(params : ExecBodyParams) {
 
             let botlock = bot.read().await;
 
+            // uses chat.say_in_reply_to() for the bot controls for messages
+            botlock
+            .botmgrs
+            .chat
+            .say_in_reply_to(
+                &params.msg, 
+                String::from("Invalid arguments"),
+                // parent_module.unwrap().clone()
+                params.clone()
+            ).await;
 
-            if parent_module.is_some() {
+
+            // if parent_module.is_some() {
                 
-                // uses chat.say_in_reply_to() for the bot controls for messages
-                botlock
-                .botmgrs
-                .chat
-                .say_in_reply_to(
-                    &params.msg, 
-                    String::from("Invalid arguments"),
-                    // parent_module.unwrap().clone()
-                    params.clone()
-                ).await;
+            //     // uses chat.say_in_reply_to() for the bot controls for messages
+            //     botlock
+            //     .botmgrs
+            //     .chat
+            //     .say_in_reply_to(
+            //         &params.msg, 
+            //         String::from("Invalid arguments"),
+            //         // parent_module.unwrap().clone()
+            //         params.clone()
+            //     ).await;
 
-            }
+            // }
 
         },
 

From f582c36f97d6c4f728ac0d665ee1c68cb5c288d1 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 15:46:37 -0400
Subject: [PATCH 60/98] clippy

---
 src/core/bot_actions.rs                  | 22 +++++++++++++++++-----
 src/core/botinstance.rs                  |  4 ++--
 src/core/botmodules.rs                   | 22 +++++++++++-----------
 src/core/chat.rs                         |  4 ++--
 src/core/identity.rs                     | 10 +++++-----
 src/custom/experimental/experiment001.rs |  8 ++++----
 src/custom/experimental/experiment002.rs |  6 +++---
 7 files changed, 44 insertions(+), 32 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index 4b17758..ac04077 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -27,7 +27,19 @@ impl ExecBodyParams {
         let parent_act = Arc::clone(&self.parent_act);
         let parent_act_lock = parent_act.read().await;
         let act = &(*parent_act_lock);
-        let parent_module = match act {
+        // let parent_module = match act {
+        //     BotAction::C(c) => {
+        //         let temp = c.module.clone();
+        //         Some(temp)
+        //     },
+        //     BotAction::L(l) => {
+        //         let temp = l.module.clone();
+        //         Some(temp)
+        //     },
+        //     _ => None
+        // };
+        // parent_module
+        match act {
             BotAction::C(c) => {
                 let temp = c.module.clone();
                 Some(temp)
@@ -37,8 +49,7 @@ impl ExecBodyParams {
                 Some(temp)
             },
             _ => None
-        };
-        parent_module
+        }
     }
 
     pub fn get_sender(&self) -> String {
@@ -57,9 +68,10 @@ impl ExecBodyParams {
             }
         }
 
-        let requestor_badge = requestor_badge_mut;
+        // let requestor_badge = requestor_badge_mut;
 
-        requestor_badge
+        // requestor_badge
+        requestor_badge_mut
     }
 
 
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index ce55ff9..ee52c2f 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -20,7 +20,7 @@ use crate::core::ratelimiter::RateLimiter;
 // use crate::core::bot_actions::actions_util::BotAR;
 use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::ModulesManager;
-use crate::core::identity::{IdentityManager, Permissible,self};
+use crate::core::identity::{IdentityManager, Permissible};
 
 use crate::core::botlog;
 use crate::core::chat::Chat;
@@ -47,7 +47,7 @@ pub enum ChangeResult {
 pub struct Channel(pub String);
 
 use super::bot_actions::ExecBodyParams;
-use super::botmodules::{BotAction, StatusType};
+use super::botmodules::StatusType;
 
 #[derive(Clone)]
 pub struct BotManagers {
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 6fded1b..a0cfc45 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -24,7 +24,7 @@ use core::panic;
 use std::collections::HashMap;
 use std::sync::Arc;
 
-use twitch_irc::message::PrivmsgMessage;
+// use twitch_irc::message::PrivmsgMessage;
 
 use casual_logger::Log;
 
@@ -33,7 +33,7 @@ use tokio::sync::RwLock;
 use async_trait::async_trait;
 
 // use self::bot_actions::actions_util::BotAR;
-use crate::core::bot_actions::BotAR;
+// use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::actions_util;
 use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{BotInstance, Channel,ChangeResult};
@@ -181,7 +181,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         // if let None = trg_module {
         if trg_module.is_none() {
 
-            let botlock = params.bot.read().await;
+            // let botlock = params.bot.read().await;
             
             let outmsg = "uuh You need to pass a module";
 
@@ -197,13 +197,13 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let botclone = Arc::clone(&bot);
             let botlock = botclone.read().await;
-            let id = botlock.get_identity();
-            let id = Arc::clone(&id);
-            let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
-            let user_roles = idlock.getspecialuserroles(
-                params.msg.sender.name.clone(), 
-                Some(Channel(params.msg.channel_login.clone()))
-            ).await;
+            // let id = botlock.get_identity();
+            // let id = Arc::clone(&id);
+            // let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+            // let user_roles = idlock.getspecialuserroles(
+            //     params.msg.sender.name.clone(), 
+            //     Some(Channel(params.msg.channel_login.clone()))
+            // ).await;
 
             botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
                 outmsg.to_string()
@@ -367,7 +367,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         //     _ => None,
         // };
 
-        let parent_module = params.get_parent_module().await;
+        // let parent_module = params.get_parent_module().await;
 
                  // [x] Unwraps arguments from message
 
diff --git a/src/core/chat.rs b/src/core/chat.rs
index f07eb55..9c365f6 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -12,7 +12,7 @@ use casual_logger::Log;
 
 use rand::Rng;
 
-use crate::core::identity::Permissible;
+// use crate::core::identity::Permissible;
 use crate::core::ratelimiter;
 use crate::core::ratelimiter::RateLimiter;
 
@@ -23,7 +23,7 @@ use crate::core::botlog;
 use tokio::time::{sleep, Duration};
 
 use super::bot_actions::ExecBodyParams;
-use super::botmodules::BotModule;
+// use super::botmodules::BotModule;
 use super::identity;
 
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 756a50d..fa3a3e2 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -8,11 +8,11 @@ use twitch_irc::message::PrivmsgMessage;
 use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util;
-use crate::core::bot_actions::BotAR;
+// use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{Channel,ChangeResult};
 use crate::core::botlog;
-use crate::core::botmodules::BotAction;
+// use crate::core::botmodules::BotAction;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
 use dotenv::dotenv;
@@ -121,7 +121,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         //     _ => None,
         // };
 
-        let parent_module = params.get_parent_module().await;
+        // let parent_module = params.get_parent_module().await;
 
         //  println!("{}",params.msg.message_text);
         botlog::trace(
@@ -331,7 +331,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         //     _ => None,
         // };
 
-        let parent_module = params.get_parent_module().await;
+        // let parent_module = params.get_parent_module().await;
         
 
         // [x] Unwraps arguments from message
@@ -540,7 +540,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         //     _ => None,
         // };
         
-        let parent_module = params.get_parent_module().await;
+        // let parent_module = params.get_parent_module().await;
 
         let mut argv = params.msg.message_text.split(' ');
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index aa9575a..f1f880f 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -13,7 +13,7 @@
 use rand::Rng;
 use std::sync::Arc;
 
-use twitch_irc::message::PrivmsgMessage;
+// use twitch_irc::message::PrivmsgMessage;
 
 use crate::core::bot_actions::ExecBodyParams;
 // use crate::core::botinstance::ChType::Channel;
@@ -21,8 +21,8 @@ use crate::core::botinstance::Channel;
 use crate::core::botlog;
 
 use crate::core::bot_actions::actions_util;
-use crate::core::bot_actions::BotAR;
-use crate::core::botmodules::BotAction;
+// use crate::core::bot_actions::BotAR;
+// use crate::core::botmodules::BotAction;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
 
 use crate::core::identity::UserRole::*;
@@ -215,7 +215,7 @@ async fn babygirl(params : ExecBodyParams) {
 
 
     
-        let parent_module = params.get_parent_module().await;
+        // let parent_module = params.get_parent_module().await;
 
 
     println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index fa4a6ce..f45e056 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -15,19 +15,19 @@ use std::sync::Arc;
 
 use chrono::{TimeZone,Local};
 
-use twitch_irc::message::PrivmsgMessage;
+// use twitch_irc::message::PrivmsgMessage;
 
 use crate::core::bot_actions::ExecBodyParams;
 // use crate::core::botinstance::ChType::Channel;
 use crate::core::botinstance::Channel;
 // use ChType::Channel;
 use crate::core::botlog;
-use crate::core::botmodules::BotAction;
+// use crate::core::botmodules::BotAction;
 
 use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util;
-use crate::core::bot_actions::BotAR;
+// use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
 use crate::core::identity::UserRole::*;

From 6912708cfbeb9ff6ffad47e9a6c78188af79a7d9 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 16:08:24 -0400
Subject: [PATCH 61/98] comments cleanup

---
 src/core/bot_actions.rs                  |  22 ---
 src/core/botinstance.rs                  |  99 -----------
 src/core/botmodules.rs                   | 144 +--------------
 src/core/chat.rs                         | 213 +----------------------
 src/core/identity.rs                     | 130 --------------
 src/custom/experimental/experiment001.rs | 115 +-----------
 src/custom/experimental/experiment002.rs | 115 ++----------
 7 files changed, 17 insertions(+), 821 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index ac04077..8941654 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -1,7 +1,6 @@
 
 use twitch_irc::message::PrivmsgMessage;
 use std::sync::Arc;
-// use tokio::sync::{Mutex, RwLock};
 use tokio::sync::RwLock;
 
 use crate::core::botinstance::BotInstance;
@@ -27,18 +26,6 @@ impl ExecBodyParams {
         let parent_act = Arc::clone(&self.parent_act);
         let parent_act_lock = parent_act.read().await;
         let act = &(*parent_act_lock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => {
-        //         let temp = c.module.clone();
-        //         Some(temp)
-        //     },
-        //     BotAction::L(l) => {
-        //         let temp = l.module.clone();
-        //         Some(temp)
-        //     },
-        //     _ => None
-        // };
-        // parent_module
         match act {
             BotAction::C(c) => {
                 let temp = c.module.clone();
@@ -67,10 +54,6 @@ impl ExecBodyParams {
                 requestor_badge_mut = Some(ChatBadge::Broadcaster);
             }
         }
-
-        // let requestor_badge = requestor_badge_mut;
-
-        // requestor_badge
         requestor_badge_mut
     }
 
@@ -87,15 +70,10 @@ pub mod actions_util {
     use std::future::Future;
     use std::pin::Pin;
 
-
-    // pub type BotAM = Arc<Mutex<BotInstance>>;
-
     pub type ExecBody = Box<
-        // dyn Fn(BotAR, PrivmsgMessage) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
         dyn Fn(ExecBodyParams) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
     >;
 
-    // pub fn asyncbox<T>(f: fn(BotAR, PrivmsgMessage) -> T) -> ExecBody
     pub fn asyncbox<T>(f: fn(ExecBodyParams) -> T) -> ExecBody
     where
         T: Future<Output = ()> + Send + 'static,
diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index ee52c2f..4bcb352 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -17,7 +17,6 @@ use casual_logger::Log;
 
 use crate::core::ratelimiter::RateLimiter;
 
-// use crate::core::bot_actions::actions_util::BotAR;
 use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::ModulesManager;
 use crate::core::identity::{IdentityManager, Permissible};
@@ -34,16 +33,8 @@ pub enum ChangeResult {
 }
 
 
-
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 
-// pub enum ChType {
-//     Channel(String),
-// }
-//
-// pub use ChType::Channel;
-//
-//simplifying from enum to struct
 pub struct Channel(pub String);
 
 use super::bot_actions::ExecBodyParams;
@@ -316,12 +307,8 @@ impl BotInstance {
 
             for a in acts {
 
-                // let act_ar = Arc::new(RwLock::new(a));
-                // let act_ar_clone = Arc::clone(&act_ar);
                 let act_clone = Arc::clone(a);
 
-                // match a {
-                // match &(*act_ar_clone.read().await) {
                 match &(*act_clone.read().await) {
                     crate::core::botmodules::BotAction::C(c) => {
                         /*
@@ -428,85 +415,6 @@ impl BotInstance {
                                 params,
                                 ).await;
 
-
-                                // if user_roles.contains(&identity::UserRole::Mod(Channel(msg.channel_login.clone()))) 
-                                // || user_roles.contains(&identity::UserRole::SupMod(Channel(msg.channel_login.clone()))) 
-                                // || user_roles.contains(&identity::UserRole::Broadcaster)
-                                // || user_roles.contains(&identity::UserRole::BotAdmin) 
-                                // {
-                    
-                    
-                                //     // self.say_in_reply_to(
-                                //     //     &params.msg, 
-                                //     //     format!("uuh You do not have the right roles to send to {}",
-                                //     //             channel_login.clone(),
-                                //     //         ), 
-                                //     //     params.clone()
-                                //     // ).await;
-                                //     let outstr =
-                                //         format!("sadg Module is disabled : {:?}",a);
-
-                                    
-                                //     let params = ExecBodyParams {
-                                //         bot : Arc::clone(&bot),
-                                //         msg : (*msg).clone(),
-                                //         parent_act : Arc::clone(&act_clone),
-                                //     };
-
-                                //     botlock.botmgrs.chat.say_in_reply_to(
-                                //         msg, 
-                                //         outstr,
-                                //         // c.module.clone()
-                                //         params,
-                                //     ).await;
-                    
-                                // }
-
-
-                                // botlog::trace(
-                                //     "ACQUIRING WRITE LOCK : ID",
-                                //     Some("BotInstance > listener_main_prvmsg()".to_string()),
-                                //     Some(msg),
-                                // );
-
-                                
-                                // const OF_CMD_CHANNEL:Channel = Channel(String::new());
-
-                                // let elevated_access = {
-                                //     let mut idlock = id.write().await;
-                                //     let (permissability, _) = idlock
-                                //         .can_user_run_prvmsg(msg, 
-                                //             vec![
-                                //                 identity::UserRole::BotAdmin,
-                                //                 identity::UserRole::Mod(OF_CMD_CHANNEL),
-                                //                 identity::UserRole::SupMod(OF_CMD_CHANNEL),
-                                //                 identity::UserRole::Broadcaster,
-                                //             ])
-                                //         .await;
-    
-                                //     permissability
-                                // };
-
-                                // if let Permissible::Allow = elevated_access {
-                                //     let botlock = bot.read().await;
-                                //     let outstr =
-                                //         format!("sadg Module is disabled : {:?}",a);
-
-                                //     let params = ExecBodyParams {
-                                //         bot : Arc::clone(&bot),
-                                //         msg : (*msg).clone(),
-                                //         parent_act : Arc::clone(&act_clone),
-
-                                //     };
-
-                                //     botlock.botmgrs.chat.say_in_reply_to(
-                                //         msg, 
-                                //         outstr,
-                                //         // c.module.clone()
-                                //         params,
-                                //     ).await;
-                                // } 
-
                                 return;
                             };
 
@@ -575,19 +483,15 @@ impl BotInstance {
                                     );
 
                                     let a = Arc::clone(&bot);
-                                    // c.execute(a, msg.clone()).await;
-                                    // c.execute(ExecBodyParams { bot : a, msg : msg.clone() }).await;
                                     c.execute(ExecBodyParams { 
                                         bot : a, 
                                         msg : msg.clone() ,
-                                        // parent_act : BotAction::C(c) ,
                                         parent_act : Arc::clone(&act_clone),
                                     }).await;
 
                                     botlog::trace(
                                         "exit out of execution",
                                         Some("BotInstance > listener_main_prvmsg()".to_string()),
-                                        // Some(&msg),
                                         Some(msg),
                                     );
                                 }
@@ -606,7 +510,6 @@ impl BotInstance {
                     crate::core::botmodules::BotAction::L(l) => {
                         
                         let botlock = bot.read().await;
-                        // let id = botlock.get_identity();
 
                         // [x] Check first if the Module for that Given Command is Enabled or Disabled on the given Channel
                         let modmgr = Arc::clone(&botlock.botmodules);
@@ -628,11 +531,9 @@ impl BotInstance {
 
                         } else {
                             let a = Arc::clone(&bot);
-                            // l.execute(a, msg.clone()).await;
                             l.execute(ExecBodyParams { 
                                 bot : a, 
                                 msg : msg.clone() , 
-                                // parent_act : BotAction::L(l) ,
                                 parent_act : Arc::clone(&act_clone),
                             } ).await;
                         }
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index a0cfc45..25206df 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -24,16 +24,12 @@ use core::panic;
 use std::collections::HashMap;
 use std::sync::Arc;
 
-// use twitch_irc::message::PrivmsgMessage;
-
 use casual_logger::Log;
 
 use tokio::sync::RwLock;
 
 use async_trait::async_trait;
 
-// use self::bot_actions::actions_util::BotAR;
-// use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::actions_util;
 use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{BotInstance, Channel,ChangeResult};
@@ -104,25 +100,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-        /*
-        
-            Get parent module 
-
-         */
-
-        //  let params_clone = Arc::clone(&params.parent_act);
-        //  let actlock = params_clone.read().await;
-        //  let act = &(*actlock);
-        //  let parent_module = match act {
-        //      BotAction::C(c) => Some(&(*c).module),
-        //      BotAction::L(l) => Some(&(*l).module),
-        //      _ => None,
-        // //  };
-
-        // let parent_module = params.get_parent_module().await;
-
-
-
 
         // [x] Unwraps arguments from message
 
@@ -197,13 +174,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             let botclone = Arc::clone(&bot);
             let botlock = botclone.read().await;
-            // let id = botlock.get_identity();
-            // let id = Arc::clone(&id);
-            // let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
-            // let user_roles = idlock.getspecialuserroles(
-            //     params.msg.sender.name.clone(), 
-            //     Some(Channel(params.msg.channel_login.clone()))
-            // ).await;
 
             botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
                 outmsg.to_string()
@@ -211,23 +181,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             params.clone(),
             ).await;
 
-
-
-            // // Only call Say if there is a parent module passed
-            // if parent_module.is_some() {
-
-        
-            //     botlock
-            //         .botmgrs
-            //         .chat
-            //         .say_in_reply_to(
-            //             &params.msg, 
-            //             outmsg.to_string() , 
-            //             // parent_module.unwrap().clone()
-            //             params.clone(),
-            //         ).await;
-            // }
-
             return;
 
         }
@@ -239,7 +192,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let trg_level = 
             if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } 
-            // else if arg1 == Some("-f") { StatusLvl::Instance }
             else { StatusLvl::Ch(Channel(currchnl)) }
             ; 
 
@@ -249,8 +201,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let modmgr = Arc::clone(&botlock.botmodules);
         let id = botlock.get_identity();
 
-
-        // modmgr.exec_enable(requestor, requestor_badge, trg_module, trg_level, id)
         let rslt = modmgr.exec_enable(
             requestor, 
             requestor_badge, 
@@ -274,26 +224,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         params.clone(),
         ).await;
 
-        
-
-        
-        // // Only call Say if there is a parent module passed
-        // if parent_module.is_some() {
-
-
-        //     botlock
-        //         .botmgrs
-        //         .chat
-        //         .say_in_reply_to(
-        //             &params.msg, 
-        //             outmsg.to_string(),
-        //             // parent_module.unwrap().clone()
-        //             params.clone(),
-        //         ).await;
-
-        // }
-
-
+    
 
     }
 
@@ -354,22 +285,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 3c. , and is -f (forced) , return a Success    
          */
 
-        /*
-            [x] Get the parent module
-        */
 
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
-
-        // let parent_module = params.get_parent_module().await;
-
-                 // [x] Unwraps arguments from message
+        // [x] Unwraps arguments from message   
 
         let (arg1, arg2) = {
 
@@ -424,7 +341,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 };
 
         // if no trg_module was passed 
-        // if let None = trg_module {
         if trg_module.is_none() {
 
             let botlock = params.bot.read().await;
@@ -437,16 +353,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 Some(&params.msg),
             );
 
-
-            // let params_clone = Arc::clone(&params.parent_act);
-            // let actlock = params_clone.read().await;
-            // let act = &(*actlock);
-            // let parent_module = match act {
-            //     BotAction::C(c) => Some(&(*c).module),
-            //     BotAction::L(l) => Some(&(*l).module),
-            //     _ => None,
-            // };
-
             // We should call a notification around here
 
             botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
@@ -455,22 +361,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             params.clone(),
             ).await;
 
-
-            // // Only call Say if there is a parent module passed
-            // if parent_module.is_some() {
-
-            //     botlock
-            //     .botmgrs
-            //     .chat
-            //     .say_in_reply_to(
-            //         &params.msg, 
-            //         outmsg.to_string(),
-            //         // ,parent_module.unwrap().clone()
-            //         params.clone()
-            //     ).await;
-
-            // }
-
             return;
 
         }
@@ -495,7 +385,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let force = arg1 == Some("-f"); 
 
-        // modmgr.exec_enable(requestor, requestor_badge, trg_module, trg_level, id)
         let rslt = modmgr.exec_disable(
             requestor, 
             requestor_badge, 
@@ -519,24 +408,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         params.clone(),
         ).await;
 
-
-        // // Only call Say if there is a parent module passed
-        // if parent_module.is_some() {
-
-        //     botlock
-        //         .botmgrs
-        //         .chat
-        //         .say_in_reply_to(
-        //             &params.msg,
-        //              outmsg.to_string(),
-        //             //  parent_module.unwrap().clone()
-        //             params.clone(),
-        //         ).await;
-
-        // }
-    
-
-
     }
 
 
@@ -558,8 +429,6 @@ impl Eq for BotModule {}
 
 impl Hash for BotModule{
     fn hash<H: Hasher>(&self, state: &mut H) {
-        // self.id.hash(state);
-        // self.phone.hash(state);
         let BotModule(name) = self.clone();
         name.to_lowercase().hash(state);
     }
@@ -591,7 +460,6 @@ pub enum BotAction {
 }
 
 impl BotAction {
-    // pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
     pub async fn execute(&self, params : ExecBodyParams) {
         match self {
             BotAction::L(a) => a.execute(params).await,
@@ -619,7 +487,6 @@ pub struct BotCommand {
 }
 
 impl BotCommand {
-    // pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
     pub async fn execute(&self, params : ExecBodyParams) {
         (*self.exec_body)(params).await;
     }
@@ -656,7 +523,6 @@ pub struct Listener {
 }
 
 impl Listener {
-    // pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) {
     pub async fn execute(&self, params : ExecBodyParams) {
         (self.exec_body)(params).await;
     }
@@ -782,7 +648,6 @@ impl ModulesManager {
 
         let dbt = self.statusdb.read().await;
          
-        // let a = dbt.entry(in_module.clone()).;
         let (mgrp,statusvector) = dbt.get(&in_module).unwrap();
 
         match mgrp {
@@ -1261,7 +1126,6 @@ impl ModulesManager {
             },
         }
         
-        // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
     pub async fn force_disable(&self, in_module: BotModule) -> (StatusType,ChangeResult) {
@@ -1305,7 +1169,6 @@ impl ModulesManager {
             },
         }
 
-        // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
     pub async fn set_instance_enabled(&self, in_module: BotModule) -> (StatusType,ChangeResult) {
@@ -1340,7 +1203,6 @@ impl ModulesManager {
             },
         }
 
-        // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
     pub async fn set_ch_disabled(&self, in_module: BotModule , in_chnl: Channel) -> (StatusType,ChangeResult) {
@@ -1378,7 +1240,6 @@ impl ModulesManager {
             },
         }
 
-        // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
     pub async fn set_ch_enabled(&self, in_module: BotModule , in_chnl: Channel) -> (StatusType,ChangeResult) {
@@ -1416,7 +1277,6 @@ impl ModulesManager {
         }
 
 
-        // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
     }
 
 
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 9c365f6..27d36e3 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -12,7 +12,6 @@ use casual_logger::Log;
 
 use rand::Rng;
 
-// use crate::core::identity::Permissible;
 use crate::core::ratelimiter;
 use crate::core::ratelimiter::RateLimiter;
 
@@ -23,7 +22,6 @@ use crate::core::botlog;
 use tokio::time::{sleep, Duration};
 
 use super::bot_actions::ExecBodyParams;
-// use super::botmodules::BotModule;
 use super::identity;
 
 
@@ -60,17 +58,12 @@ impl Chat {
         self.ratelimiters.lock().await.insert(chnl, n);
     }
 
-
-
-
-    // async fn send_botmsg(&self, msginput: BotMsgType<'_>) {
     #[async_recursion]
-    // async fn send_botmsg(&self, msginput: BotMsgType<'_>, params : ExecBodyParams) {
     pub async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
 
         
             
-                /*
+        /*
         formats message before sending to TwitchIRC
 
         - [x] Custom String Formatting (e.g., adding random black spaces)
@@ -95,7 +88,6 @@ impl Chat {
                 (a.clone(),b.clone())
             },
             BotMsgType::Notif(outmsg) => {
-                // (msg.channel_login.clone(),outmsg)
                 (params.msg.channel_login.clone(),outmsg)
             }
         };
@@ -110,7 +102,6 @@ impl Chat {
         );
 
         let parent_module = params.get_parent_module().await;
-        // let parent_module = parent_module.clone();
 
         let params_clone = params.clone();
         let botclone = Arc::clone(&params_clone.bot);
@@ -121,36 +112,6 @@ impl Chat {
             Channel(channel_login.clone())
             ).await;
 
-
-        // botlog::trace(
-        //     "BEFORE GET_CHANNEL_STATUS",
-        // Some("chat.rs > send_botmsg ".to_string()),
-        // Some(&params.msg),
-        // );
-
-        // let rslt = self.client.get_channel_status(channel_login.clone()).await == (false,false);
-        
-        // botlog::trace(
-        //     format!("GET_CHANNEL_STATUS result = {:?}",rslt).as_str(),
-        // Some("chat.rs > send_botmsg ".to_string()),
-        // Some(&params.msg),
-        // );
-
-        // Log::flush();
-
-
-
-        // if rslt {
-        //     // in the case where the provided channel isn't something we're known to be connected to
-
-        //     botlog::warn(
-        //         &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
-        //         Some("Chat > send_botmsg".to_string()),
-        //         None,
-        //     );
-        //     return ;
-        // }
-
         if !params.bot.read().await.bot_channels.contains(&Channel(channel_login.clone())) {
             botlog::warn(
                 &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
@@ -158,18 +119,8 @@ impl Chat {
                 None,
             );
 
-            // self.say_in_reply_to(
-            //     &params.msg, 
-            //     "uuh Bot can't send to a channel it isn't joined".to_string(), 
-            //     params.clone()
-            // ).await;
             if let BotMsgType::SayInReplyTo(_prvmsg,_outmsg) = msginput {
 
-                // self.say_in_reply_to(
-                //     a, 
-                //     "uuh Bot can't send to a channel it isn't joined".to_string(), 
-                //     params.clone()
-                // ).await;
                 self.send_botmsg(BotMsgType::Notif(
                     "uuh Bot can't send to a channel it isn't joined".to_string(), 
                 ), 
@@ -192,13 +143,6 @@ impl Chat {
 
         */
 
-
-        // match modstatus {
-        //     super::botmodules::StatusType::Enabled(_) => (),
-        //     super::botmodules::StatusType::Disabled(_) => (),
-        // }
-
-                        
         botlog::trace(
             format!("BEFORE modstatus check : modstatus = {:?}",modstatus).as_str(),
         Some("chat.rs > send_botmsg ".to_string()),
@@ -263,7 +207,7 @@ impl Chat {
         
             /* 
             
-                [ ] !! => 03.24 - Would be nice if around here , validate the user has at least some special roles in target channel
+                [x] !! => 03.24 - Would be nice if around here , validate the user has at least some special roles in target channel
                     - NOTE : If these need to be refined, they can be by the custom module developer at the parent calling function of say()
                     - This just prevents Chat from being triggered in a channel where the sending chatter does not have any special roles
 
@@ -271,8 +215,6 @@ impl Chat {
 
             
 
-
-
             /*
             
                 Use 
@@ -290,7 +232,7 @@ impl Chat {
              let botlock = botclone.read().await;
              let id = botlock.get_identity();
              let id = Arc::clone(&id);
-             let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
+             let idlock = id.read().await; // <-- [x] 03.24 - seems to work
              let user_roles = idlock.getspecialuserroles(
                 params.get_sender(), 
                 Some(Channel(channel_login.clone()))
@@ -304,18 +246,10 @@ impl Chat {
 
             Log::flush();
 
-            // [ ] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send
+            // [x] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send
             // - Otherwise if not (checked here) , this will not run
             // - NOTE : For now, I've removed BotAdmin just for curiosity - BotAdmins can always elevate themselves if they want
 
-            // if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
-            //     || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
-            //     || user_roles.contains(&identity::UserRole::Broadcaster)) 
-            // if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
-            // || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
-            // || user_roles.contains(&identity::UserRole::Broadcaster)
-            // || user_roles.contains(&identity::UserRole::BotAdmin)) 
-
             if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
             || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
             || user_roles.contains(&identity::UserRole::Broadcaster)
@@ -323,14 +257,6 @@ impl Chat {
             {
 
 
-                // self.say_in_reply_to(
-                //     &params.msg, 
-                //     format!("uuh You do not have the right roles to send to {}",
-                //             channel_login.clone(),
-                //         ), 
-                //     params.clone()
-                // ).await;
-
                 match msginput {
                     BotMsgType::Notif(_) => {
                         // If Sender is Not a BotAdmin, don't do anything about the notification and return
@@ -382,137 +308,6 @@ impl Chat {
 
              */
 
-            /*
-
-             botlog::trace(
-                "BEFORE Permissibility checks",
-            Some("chat.rs > send_botmsg ".to_string()),
-            Some(&params.msg),
-            );
-
-            Log::flush();
-    
-
-            const OF_CMD_CHANNEL:Channel = Channel(String::new());
-
-            let permissability = Permissible::Allow;
-
-            {
-
-                
-                // let id = botlock.get_identity();
-                // let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
-                let channel_login_clone = channel_login.clone();
-
-                
-                let spawnhandle = tokio::spawn( 
-                    async move {
-                        let botclone = Arc::clone(&params_clone.bot);
-                        let botlock = botclone.read().await;
-                        let id = botlock.get_identity();
-
-                        
-                        // botlog::trace(
-                        //     "ACQUIRING WRITE LOCK : ID",
-                        //     Some("Chat > send_botmsg".to_string()),
-                        //     Some(&params.msg),
-                        // );
-
-
-                        // {
-                        // let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
-                        // }
-
-                        // botlog::trace(
-                        //     "ACQUIRED WRITE LOCK : ID",
-                        //     Some("Chat > send_botmsg".to_string()),
-                        //     Some(&params.msg),
-                        // );
-
-                        // let (permissability, _) = idlock
-                        // .can_user_run(
-                        //     params.get_sender(),
-                        //     Channel(channel_login_clone),
-                        //     params.get_sender_chatbadge(),
-                        //                         vec![
-                        //         //identity::UserRole::BotAdmin,
-                        //         identity::UserRole::Mod(OF_CMD_CHANNEL),
-                        //         identity::UserRole::SupMod(OF_CMD_CHANNEL),
-                        //         identity::UserRole::Broadcaster,
-                        //     ]
-                        // ).await;
-                        // permissability
-                    }
-                );
-
-                if let Ok(permissibility) = spawnhandle.await {
-                    botlog::trace(
-                        format!("permisibility check : {:?}",permissability).as_str(),
-                    Some("chat.rs > send_botmsg ".to_string()),
-                    None
-                    );
-        
-                }
-
-
-            }
-
-
-    
-
-            // let permissability = {
-                // let id = botlock.get_identity();
-                // let mut idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
-            //     let (permissability, _) = idlock
-            //         .can_user_run(
-            //             params.get_sender(),
-            //             Channel(channel_login.clone()),
-            //             params.get_sender_chatbadge(),
-            //                                 vec![
-            //                 //identity::UserRole::BotAdmin,
-            //                 identity::UserRole::Mod(OF_CMD_CHANNEL),
-            //                 identity::UserRole::SupMod(OF_CMD_CHANNEL),
-            //                 identity::UserRole::Broadcaster,
-            //             ]
-            //         ).await;
-            //     permissability
-            // };
-
-            // match permissability {
-            //     Permissible::Allow => (),
-            //     Permissible::Block => (),
-            // }
-
-
-            botlog::trace(
-                format!("permisibility check : {:?}",permissability).as_str(),
-            Some("chat.rs > send_botmsg ".to_string()),
-            None,
-            );
-
-            Log::flush();
-
-            if let Permissible::Block = permissability {
-
-
-                if let BotMsgType::SayInReplyTo(a, _) = msginput {
-                
-                    // self.say_in_reply_to(
-                    //     a, 
-                    //     format!("uuh you don't have special privileges in {}",
-                    //             channel_login.clone()
-                    //          ), 
-                    //     params.clone()
-                    // ).await;
-    
-                }
-                return
-
-            }
-
-        
-            */
-
         let rl = Arc::clone(&self.ratelimiters);
         let mut rllock = rl.lock().await;
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index fa3a3e2..2fbf56e 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -8,11 +8,9 @@ use twitch_irc::message::PrivmsgMessage;
 use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util;
-// use crate::core::bot_actions::BotAR;
 use crate::core::bot_actions::ExecBodyParams;
 use crate::core::botinstance::{Channel,ChangeResult};
 use crate::core::botlog;
-// use crate::core::botmodules::BotAction;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
 use dotenv::dotenv;
@@ -70,10 +68,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ],
     };
 
-    // tempb.add_to_modmgr(Arc::clone(&mgr)).await;
     tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
-    // async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) {
     async fn cmd_promote(params : ExecBodyParams) {
         botlog::trace(
             "Called cmd promote",
@@ -107,22 +103,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-
-        /*
-            [x] Get the parent module
-        */
-
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
-
-        // let parent_module = params.get_parent_module().await;
-
         //  println!("{}",params.msg.message_text);
         botlog::trace(
             format!("Twich Message > {}", params.msg.message_text).as_str(),
@@ -200,7 +180,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             None => {
                 botlog::debug(
-                    // &format!("No Targer User argument"),
                     "No Targer User argument",
                     Some("identity.rs > cmd_demote()".to_string()),
                     None,
@@ -240,24 +219,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ).await;
 
 
-        // // Only call Say if there is a parent module passed
-        // if parent_module.is_some() {
-
-
-        //     botlock
-        //         .botmgrs
-        //         .chat
-        //         .say_in_reply_to(
-        //                 &params.msg, 
-        //                 outmsg.to_string(),
-        //                 // parent_module.unwrap().clone()
-        //                 params.clone(),
-        //         ).await;
-
-        // }
-
         botlog::trace(
-            // &format!("End of cmd_promote()"),
             "End of cmd_promote()",
             Some("identity.rs > cmd_prommote()".to_string()),
             None,
@@ -278,11 +240,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ],
     };
 
-    // tempb.add_to_modmgr(Arc::clone(&mgr)).await;
-    // add_core_to_modmgr
     tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
-    // async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) {
     async fn cmd_demote(params : ExecBodyParams) {
         botlog::debug(
             "Called cmd demote",
@@ -317,23 +276,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-
-        /*
-            [x] Get the parent module
-        */
-
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
-
-        // let parent_module = params.get_parent_module().await;
-        
-
         // [x] Unwraps arguments from message
 
         let (arg1, _arg2) = {
@@ -413,7 +355,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         let rslt = match targetusr {
             Some(targetusr) => {
                 botlog::debug(
-                    // &format!("running demote()"),
                     "running demote()",
                     Some("identity.rs > cmd_demote()".to_string()),
                     None,
@@ -432,7 +373,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             None => {
                 botlog::debug(
-                    // &format!("No Targer User argument"),
                     "No Targer User argument",
                     Some("identity.rs > cmd_demote()".to_string()),
                     None,
@@ -474,23 +414,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ).await;
 
 
-        // // Only call Say if there is a parent module passed
-        // if parent_module.is_some() {
-
-        //     botlock
-        //         .botmgrs
-        //         .chat
-        //         .say_in_reply_to(
-        //             &params.msg, 
-        //         outmsg.to_string(),
-        //             // parent_module.unwrap().clone()
-        //             params.clone()
-        //         ).await;
-
-        // }
-
-
-
     }
 
     let tempcomm = BotCommand {
@@ -507,11 +430,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         ],
     };
 
-    // tempcomm.add_to_modmgr(Arc::clone(&mgr)).await;
-    // add_core_to_modmgr
     tempcomm.add_core_to_modmgr(Arc::clone(&mgr)).await;
 
-    // async fn getroles(bot: BotAR, msg: PrivmsgMessage) {
     async fn getroles(params : ExecBodyParams) {
         botlog::debug(
             "Called cmd getroles",
@@ -527,20 +447,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
          */
 
-        /*  
-            [x] Get the parent module
-        */
-
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
-        
-        // let parent_module = params.get_parent_module().await;
 
         let mut argv = params.msg.message_text.split(' ');
 
@@ -613,7 +519,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         );
 
         botlog::trace(
-            // &format!("Evaluating special roles"),
             "Evaluating special roles",
             Some("identity.rs > init > getroles()".to_string()),
             Some(&params.msg),
@@ -659,17 +564,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         params.clone(),
         ).await;
 
-        // if parent_module.is_some() {
-
-        //     botlock.botmgrs.chat.say_in_reply_to(
-        //         &params.msg, 
-        //         outmsg,
-        //         // parent_module.unwrap().clone()
-        //         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
     }
@@ -716,13 +610,6 @@ pub enum ChatBadge {
     Mod,
 }
 
-// #[derive(Debug, PartialEq, Eq)]
-// pub enum ChangeResult {
-//     Success(String),
-//     Failed(String),
-//     NoChange(String),
-// }
-
 impl IdentityManager {
     pub fn init() -> IdentityManager {
         let mut a = HashMap::new();
@@ -790,7 +677,6 @@ impl IdentityManager {
         botlog::trace(
             "Checking within PRVMSG",
             Some("identity.rs > can_user_run_PRVMSG()".to_string()),
-            // Some(&msg),
             Some(msg),
         );
 
@@ -806,7 +692,6 @@ impl IdentityManager {
 
         self.can_user_run(
             msg.sender.name.to_owned(),
-            // Channel::construct(msg.channel_login.to_owned()),
             Channel(msg.channel_login.to_owned()),
             sender_badge,
             cmdreqroles,
@@ -822,7 +707,6 @@ impl IdentityManager {
         chat_badge: Option<ChatBadge>,
         cmdreqroles: Vec<UserRole>, // ) -> Result<Permissible,Box<dyn Error>> {
     ) -> (Permissible, ChangeResult) {
-        // println!{"Checking within can_user_run()"};
         botlog::debug(
             &format!(
                 "Checking within can_user_run() : 
@@ -869,8 +753,6 @@ impl IdentityManager {
 
         // [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow)
 
-        // let idar = Arc::new(RwLock::new(self));
-
         let usr = usr.to_lowercase();
 
 
@@ -891,9 +773,7 @@ impl IdentityManager {
             );
         } 
 
-        // if cmdreqroles.len() == 0 {
         if cmdreqroles.is_empty() {
-            // return Ok(Permissible::Allow)
             return (
                 Permissible::Allow,
                 ChangeResult::NoChange("Command has no required cmdreqroles".to_string()),
@@ -907,10 +787,6 @@ impl IdentityManager {
             // [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow)
             // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("")  , Ok(Permissible::Allow)
             Some(ChatBadge::Broadcaster) => {
-                // if cmdreqroles.contains(&UserRole::Broadcaster)
-                //     || cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new())))
-                //     || cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new())))
-                // {
                 if cmdreqroles.contains(&UserRole::Broadcaster)
                     || cmdreqroles.contains(&UserRole::Mod(Channel(String::new())))
                     || cmdreqroles.contains(&UserRole::SupMod(Channel(String::new())))
@@ -982,7 +858,6 @@ impl IdentityManager {
             None,
         );
 
-        // if cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) {
         if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) {
             botlog::trace(
                 "Command requires Mod Role",
@@ -1019,7 +894,6 @@ impl IdentityManager {
 
         // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
 
-        // if cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) {
             if cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) {
             if let Some(a) = self
                 .special_roles_users
@@ -1564,7 +1438,6 @@ mod core_identity {
         let test_id_mgr = IdentityManager::init();
 
         // [x] Broadcaster Promotes Chatter to SupMod
-        // let channel = Some(Channel::construct("broadcasterer".to_string()));
         let channel = Some(Channel("broadcasterer".to_string()));
         let trgchatter = "regularChatter".to_string();
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
@@ -1644,7 +1517,6 @@ mod core_identity {
 
         let broadcaster = "broadcasterer".to_string();
         let broadcaster_badge = &Some(ChatBadge::Broadcaster);
-        // let channel = Some(ChType::Channel(broadcaster.clone()));
         let channel = Channel(broadcaster.clone());
         let supchatter = "superModerator".to_string();
         let trg_role = None;
@@ -1687,7 +1559,6 @@ mod core_identity {
 
         // [x] SupMod Attempts to Promote Chatter to SupMod
 
-        // let broadcaster = "broadcasterer".to_string();
         let authorizer = supchatter;
         let authorizer_badge = &Some(ChatBadge::Broadcaster);
         let channel = Some(Channel(broadcaster.clone()));
@@ -1758,7 +1629,6 @@ mod core_identity {
 
         // [x] SupMod Attempts to Promote Chatter to SupMod
 
-        // let broadcaster = "broadcasterer".to_string();
         let authorizer = botadmin;
         let authorizer_badge = botadmin_badge;
         let channel = Some(Channel("somechannel".to_string()));
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index f1f880f..58d0c59 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -13,16 +13,11 @@
 use rand::Rng;
 use std::sync::Arc;
 
-// use twitch_irc::message::PrivmsgMessage;
-
 use crate::core::bot_actions::ExecBodyParams;
-// use crate::core::botinstance::ChType::Channel;
 use crate::core::botinstance::Channel;
 use crate::core::botlog;
 
 use crate::core::bot_actions::actions_util;
-// use crate::core::bot_actions::BotAR;
-// use crate::core::botmodules::BotAction;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
 
 use crate::core::identity::UserRole::*;
@@ -62,18 +57,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     list1.add_to_modmgr(Arc::clone(&mgr)).await;
 
-
-    //     // 1. Define the BotAction
-    // let list1 = Listener {
-    //         module: BotModule(String::from("experiments001")),
-    //         name: String::from("babygirl Listener"),
-    //         exec_body: actions_util::asyncbox(babygirl),
-    //         help: String::from(""),
-    //     };
-    
-    //     // 2. Add the BotAction to ModulesManager
-    //     list1.add_to_modmgr(Arc::clone(&mgr)).await;
-
     // 1. Define the BotAction
     let botc1 = BotCommand {
         module: BotModule(String::from("experiments001")),
@@ -112,21 +95,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
 }
 
-// async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
-    async fn good_girl(params : ExecBodyParams) {
-
-
-    // let params_clone = Arc::clone(&params.parent_act);
-    // let actlock = params_clone.read().await;
-    // let act = &(*actlock);
-    // let parent_module = match act {
-    //     BotAction::C(c) => Some(&(*c).module),
-    //     BotAction::L(l) => Some(&(*l).module),
-    //     _ => None,
-    // };
-
-    
-    // let parent_module = params.get_parent_module().await;
+async fn good_girl(params : ExecBodyParams) {
 
     // [ ] Uses gen_ratio() to output bool based on a ratio probability .
     //   - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator)
@@ -134,7 +103,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
     if params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
         || params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
-    // if params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
     {
         botlog::debug(
             "Good Girl Detected > Pausechamp",
@@ -163,30 +131,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
             .say_in_reply_to(
                 &params.msg, 
                 String::from("GoodGirl xdd "),
-                // parent_module.unwrap().clone()
                 params.clone()
             ).await;
 
-            // if parent_module.is_some() {
-
-            //     // uses chat.say_in_reply_to() for the bot controls for messages
-            //     botlock
-            //         .botmgrs
-            //         .chat
-            //         .say_in_reply_to(
-            //             &params.msg, 
-            //             String::from("GoodGirl xdd "),
-            //             // parent_module.unwrap().clone()
-            //             params.clone()
-            //         ).await;
-
-            // }
 
         }
     }
 }
 
-// async fn testy(mut _chat: BotAR, msg: PrivmsgMessage) {
 async fn testy(params : ExecBodyParams) {
     println!("testy triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
@@ -197,26 +149,8 @@ async fn testy(params : ExecBodyParams) {
 }
 
 
-// async fn babygirl(bot: BotAR, msg: PrivmsgMessage) {
 async fn babygirl(params : ExecBodyParams) {
 
-        /*
-            [x] Get the parent module
-        */
-
-        // let params_clone = Arc::clone(&params.parent_act);
-        // let actlock = params_clone.read().await;
-        // let act = &(*actlock);
-        // let parent_module = match act {
-        //     BotAction::C(c) => Some(&(*c).module),
-        //     BotAction::L(l) => Some(&(*l).module),
-        //     _ => None,
-        // };
-
-
-    
-        // let parent_module = params.get_parent_module().await;
-
 
     println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
@@ -231,8 +165,6 @@ async fn babygirl(params : ExecBodyParams) {
     let botlock = bot.read().await;
 
 
-
-    // uses chat.say_in_reply_to() for the bot controls for messages
     botlock
         .botmgrs
         .chat
@@ -268,54 +200,9 @@ async fn babygirl(params : ExecBodyParams) {
 
 
 
-    // if parent_module.is_some() {
-
-    //     // uses chat.say_in_reply_to() for the bot controls for messages
-    //     botlock
-    //         .botmgrs
-    //         .chat
-    //         .say_in_reply_to(
-    //             &params.msg, 
-    //             String::from("16:13 notohh: cafdk"),
-    //             // parent_module.clone().unwrap().clone()
-    //             params.clone()
-    //         ).await;
-
-
-    //     sleep(Duration::from_secs_f64(0.5)).await;
-
-    //     botlock
-    //     .botmgrs
-    //     .chat
-    //     .say_in_reply_to(
-    //         &params.msg, 
-    //         String::from("16:13 notohh: have fun eating princess"),
-    //         // parent_module.clone().unwrap().clone()
-    //         params.clone()
-    //     ).await;
-
-
-    //     sleep(Duration::from_secs_f64(2.0)).await;
-
-    //     botlock
-    //     .botmgrs
-    //     .chat
-    //     .say_in_reply_to(
-    //         &params.msg, 
-    //         String::from("16:13 notohh: baby girl"),
-    //         // parent_module.unwrap().clone()
-    //         params.clone()
-    //     ).await;
-
-    // }
-
-
 }
 
 
-
-
-// async fn routinelike(_bot: BotAR, msg: PrivmsgMessage) {
 async fn routinelike(params : ExecBodyParams) {
     println!("routinelike triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index f45e056..3be88ac 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -10,30 +10,22 @@
 
 */
 
-// use rand::Rng;
 use std::sync::Arc;
 
 use chrono::{TimeZone,Local};
 
-// use twitch_irc::message::PrivmsgMessage;
 
 use crate::core::bot_actions::ExecBodyParams;
-// use crate::core::botinstance::ChType::Channel;
 use crate::core::botinstance::Channel;
-// use ChType::Channel;
 use crate::core::botlog;
-// use crate::core::botmodules::BotAction;
 
 use casual_logger::Log;
 
 use crate::core::bot_actions::actions_util;
-// use crate::core::bot_actions::BotAR;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 
 use crate::core::identity::UserRole::*;
 
-// use tokio::time::{sleep, Duration};
-
 pub async fn init(mgr: Arc<ModulesManager>) {
 
     const OF_CMD_CHANNEL:Channel = Channel(String::new());
@@ -57,16 +49,13 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     botc1.add_to_modmgr(Arc::clone(&mgr)).await;
 
-    // If enabling by defauling at instance level
-    mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await;
-
-    // [ ] #TODO - FOR SOME REASON, IF DISABLED BY DEFAULT, IT OVERFLOWS at RUNGTIME
+    // If enabling by defauling at instance level , uncomment the following
+    // mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await;
 
 
 }
 
 
-// async fn sayout(bot: BotAR, msg: PrivmsgMessage) {
 async fn sayout(params : ExecBodyParams) {
 
 
@@ -77,32 +66,16 @@ async fn sayout(params : ExecBodyParams) {
 
 
 
-     
-        /*
-            [x] Get the parent module
-        */
-
-    let parent_module = params.get_parent_module().await;
-
-
-
     let reply_parent = if let Some(Some(reply)) = params.msg.source.tags.0.get("reply-parent-msg-body") {
             Some(reply)
         } else { None }
     ;
 
 
-    // let reply_parent_usr = if let Some(Some(reply)) = msg.source.tags.0.get("reply-thread-parent-user-login") {
-    //     Some(reply)
-    //     } else { None }
-    // ;
-
     let reply_parent_ts = if let Some(Some(replyts)) = params.msg.source.tags.0.get("tmi-sent-ts") {
 
         let a: i64 = replyts.parse().unwrap();
         let b = Local.timestamp_millis_opt(a).unwrap();
-        // println!("Output : {}",b.to_string());
-        // println!("Formatted : {}",b.format("%m-%d %H:%M") );
         Some(b.format("%m-%d %H:%M"))
         } else { None }
     ;
@@ -145,35 +118,6 @@ async fn sayout(params : ExecBodyParams) {
                 None,
             );
 
-            // // if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) {
-            // if !botlock.bot_channels.contains(&Channel(trgchnl.to_lowercase().to_string().clone())) {
-
-            //     // in the case where the provided channel isn't something we're known to be connected to
-            //     botlog::warn(
-            //         &format!("A message attempted to send for a Non-Joined Channel : {}",trgchnl.to_string().clone()),
-            //         Some("Chat > send_botmsg".to_string()),
-            //         None,
-            //     );
-            //     // return ;
-
-            //     if parent_module.clone().is_some() {
-
-                    
-            //         botlock
-            //         .botmgrs
-            //         .chat
-            //         .say_in_reply_to(
-            //             &params.msg, 
-            //             format!("Not a Joined Channel : {}",trgchnl),
-            //             // parent_module.clone().unwrap().clone()
-            //             params.clone(),
-            //         ).await;
-
-            //     }
-
-
-            // }
-
             /*
                 1. If a Reply , 
                 [ ] Get Parent Content message - reply_parent
@@ -194,48 +138,26 @@ async fn sayout(params : ExecBodyParams) {
             
             let newoutmsg = if let Some(srcmsg) = reply_parent {
 
-                // format!("{} from #{} says {} . Replying to: {} : {}",
-                //     msg.sender.name,msg.channel_login,outmsg, reply_parent_usr.unwrap(),srcmsg)
-                // format!("{} from #{} says {} @ {} {} : {}",
-                //     msg.sender.name,
-                //     msg.channel_login,
-                //     outmsg,
-                //     reply_parent_ts.unwrap(), 
-                //     reply_parent_usr.unwrap(),
-                //     srcmsg)
                 format!("{} {} @ {} : {}",
                     reply_parent_ts.unwrap(),
                     params.msg.sender.name,
                     params.msg.channel_login,
                     srcmsg)
             } else {
-                // format!("{} from #{} says : {}",
-                //     msg.sender.name,
-                //     msg.channel_login, 
-                //     outmsg)
                 format!("in {} - {} : {}",
                     params.msg.channel_login,
                     params.msg.sender.name, 
                     outmsg)
             };
 
-            
-            if parent_module.clone().is_some() {
-
-
-                // uses chat.say_in_reply_to() for the bot controls for messages
-                botlock
-                    .botmgrs
-                    .chat
-                    .say(
-                        trgchnl.to_string(), 
-                        newoutmsg.to_string(),
-                    // parent_module.unwrap().clone()
-                        params.clone(),
-                    ).await;
-
-            }
-
+            botlock
+                .botmgrs
+                .chat
+                .say(
+                    trgchnl.to_string(), 
+                    newoutmsg.to_string(),
+                    params.clone(),
+                ).await;
 
 
         },
@@ -257,30 +179,13 @@ async fn sayout(params : ExecBodyParams) {
             .say_in_reply_to(
                 &params.msg, 
                 String::from("Invalid arguments"),
-                // parent_module.unwrap().clone()
                 params.clone()
             ).await;
 
 
-            // if parent_module.is_some() {
-                
-            //     // uses chat.say_in_reply_to() for the bot controls for messages
-            //     botlock
-            //     .botmgrs
-            //     .chat
-            //     .say_in_reply_to(
-            //         &params.msg, 
-            //         String::from("Invalid arguments"),
-            //         // parent_module.unwrap().clone()
-            //         params.clone()
-            //     ).await;
-
-            // }
-
         },
 
     }
 
-
     Log::flush();
 }
\ No newline at end of file

From 1129e0d28a0779536e6e2d97ac3d64ccc3451640 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 17:01:27 -0400
Subject: [PATCH 62/98] recognizes VIP badge

---
 src/core/botmodules.rs |  4 ++++
 src/core/identity.rs   | 13 ++++++++++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 25206df..188b560 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -143,6 +143,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 requestor_badge_mut = Some(ChatBadge::Mod);
             } else if b.name == "broadcaster" {
                 requestor_badge_mut = Some(ChatBadge::Broadcaster);
+            } else if b.name == "vip" {
+                requestor_badge_mut = Some(ChatBadge::VIP);
             }
         }
 
@@ -330,6 +332,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 requestor_badge_mut = Some(ChatBadge::Mod);
             } else if b.name == "broadcaster" {
                 requestor_badge_mut = Some(ChatBadge::Broadcaster);
+            } else if b.name == "vip" {
+                requestor_badge_mut = Some(ChatBadge::VIP);
             }
         }
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 2fbf56e..03d4a6a 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -127,8 +127,10 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 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();
 
@@ -327,8 +329,10 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                 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;
 
@@ -608,6 +612,7 @@ pub struct IdentityManager {
 pub enum ChatBadge {
     Broadcaster,
     Mod,
+    VIP,
 }
 
 impl IdentityManager {
@@ -687,8 +692,10 @@ impl IdentityManager {
                 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);
             }
-        }
+        };
 
         self.can_user_run(
             msg.sender.name.to_owned(),

From 38e7060d86fdefb26f75e5bee5a26066a4fbc5fe Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 17:46:57 -0400
Subject: [PATCH 63/98] auto VIP

---
 src/core/botinstance.rs                  |  53 +++++++++-
 src/core/botmodules.rs                   |   6 +-
 src/core/chat.rs                         |   2 +
 src/core/identity.rs                     | 121 +++++++++++++++++++----
 src/custom/experimental/experiment001.rs |   6 +-
 src/custom/experimental/experiment002.rs |   9 +-
 6 files changed, 168 insertions(+), 29 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 4bcb352..e9d83cf 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -465,12 +465,55 @@ impl BotInstance {
 
                                     };
 
-                                    botlock.botmgrs.chat.say_in_reply_to(
-                                        msg, 
-                                        outstr,
-                                        // c.module.clone(),
-                                        params
+                                    botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                                        outstr.to_string()
+                                        ),
+                                    params.clone(),
                                     ).await;
+
+
+                                    // botlock.botmgrs.chat.say_in_reply_to(
+                                    //     msg, 
+                                    //     outstr,
+                                    //     // c.module.clone(),
+                                    //     params
+                                    // ).await;
+                                }
+
+                                if innerstr
+                                    .to_lowercase()
+                                    .contains(&"Auto Promoted VIP".to_lowercase())
+                                {
+                                    botlog::notice(
+                                        "Assigning VIP UserRole to VIP",
+                                        Some("botinstance > listener_main_prvmsg()".to_string()),
+                                        Some(msg),
+                                    );
+
+                                    let botlock = bot.read().await;
+                                    let outstr =
+                                        "❤️ a VIP - love ya!".to_string();
+
+                                    
+                                    let params = ExecBodyParams {
+                                        bot : Arc::clone(&bot),
+                                        msg : (*msg).clone(),
+                                        parent_act : Arc::clone(&act_clone),
+
+                                    };
+
+                                    botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                                        outstr.to_string()
+                                        ),
+                                    params.clone(),
+                                    ).await;
+
+                                    // botlock.botmgrs.chat.say_in_reply_to(
+                                    //     msg, 
+                                    //     outstr,
+                                    //     // c.module.clone(),
+                                    //     params
+                                    // ).await;
                                 }
                             }
 
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index 188b560..c104fdd 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -19,6 +19,10 @@ Example
 
 */
 
+
+const OF_CMD_CHANNEL:Channel = Channel(String::new());
+
+
 use core::panic;
 
 use std::collections::HashMap;
@@ -45,8 +49,6 @@ use super::identity::ChatBadge;
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:Channel = Channel(String::new());
-
     // 1. Define the BotAction
     let botc1 = BotCommand {
         module: BotModule(String::from("core")),
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 27d36e3..bb938cc 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -249,10 +249,12 @@ impl Chat {
             // [x] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send
             // - Otherwise if not (checked here) , this will not run
             // - NOTE : For now, I've removed BotAdmin just for curiosity - BotAdmins can always elevate themselves if they want
+            // - Will be adding VIP to this as this should include Channel_Level Roles
 
             if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) 
             || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) 
             || user_roles.contains(&identity::UserRole::Broadcaster)
+            || user_roles.contains(&identity::UserRole::VIP(Channel(channel_login.clone())))
             ) 
             {
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 03d4a6a..5f9a1d0 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -1,3 +1,8 @@
+
+
+const OF_CMD_CHANNEL:Channel = Channel(String::new());
+
+
 use std::collections::HashMap;
 use std::sync::Arc;
 
@@ -61,8 +66,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         exec_body: actions_util::asyncbox(cmd_promote),
         help: String::from("promote"),
         required_roles: vec![
-            UserRole::Mod(Channel(String::new())),
-            UserRole::SupMod(Channel(String::new())),
+            UserRole::Mod(OF_CMD_CHANNEL),
+            UserRole::SupMod(OF_CMD_CHANNEL),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -235,8 +240,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         exec_body: actions_util::asyncbox(cmd_demote),
         help: String::from("demote"),
         required_roles: vec![
-            UserRole::Mod(Channel(String::new())),
-            UserRole::SupMod(Channel(String::new())),
+            UserRole::Mod(OF_CMD_CHANNEL),
+            UserRole::SupMod(OF_CMD_CHANNEL),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -427,8 +432,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         exec_body: actions_util::asyncbox(getroles),
         help: String::from("getroles"),
         required_roles: vec![
-            UserRole::Mod(Channel(String::new())),
-            UserRole::SupMod(Channel(String::new())),
+            UserRole::Mod(OF_CMD_CHANNEL),
+            UserRole::SupMod(OF_CMD_CHANNEL),
             UserRole::Broadcaster,
             UserRole::BotAdmin,
         ],
@@ -492,6 +497,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     )
                     .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(
@@ -536,6 +543,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             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(
@@ -584,8 +593,9 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum UserRole {
     Chatter,
-    Mod(Channel),    // String specifies Channel
-    SupMod(Channel), // String specifies Channel
+    Mod(Channel),   
+    SupMod(Channel), 
+    VIP(Channel), 
     Broadcaster,
     BotAdmin,
 }
@@ -787,7 +797,7 @@ impl IdentityManager {
             );
         }
 
-        let mut modrolechange = ChangeResult::NoChange("".to_string());
+        let mut rolechange = ChangeResult::NoChange("".to_string());
 
         match chat_badge {
             // [x] If chatBadge::Broadcaster  ...
@@ -795,8 +805,8 @@ impl IdentityManager {
             // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("")  , Ok(Permissible::Allow)
             Some(ChatBadge::Broadcaster) => {
                 if cmdreqroles.contains(&UserRole::Broadcaster)
-                    || cmdreqroles.contains(&UserRole::Mod(Channel(String::new())))
-                    || cmdreqroles.contains(&UserRole::SupMod(Channel(String::new())))
+                    || cmdreqroles.contains(&UserRole::Mod(OF_CMD_CHANNEL))
+                    || cmdreqroles.contains(&UserRole::SupMod(OF_CMD_CHANNEL))
                 {
                     // return Ok(Permissible::Allow)
                     return (
@@ -850,7 +860,48 @@ impl IdentityManager {
 
                         usrroles_lock.push(UserRole::Mod(channelname.clone()));
 
-                        modrolechange = ChangeResult::Success("Auto Promoted Mod".to_string());
+                        rolechange = ChangeResult::Success("Auto Promoted Mod".to_string());
+                    }
+                }
+            }
+            Some(ChatBadge::VIP) => {
+                botlog::info(
+                    "VIP Chatbadge detected",
+                    Some("identity.rs > can_user_run()".to_string()),
+                    None,
+                );
+
+                let rolesdb = Arc::clone(&self.special_roles_users);
+
+                self.affirm_chatter_in_db(usr.clone()).await;
+
+                let rolesdb_lock = rolesdb.write().await;
+
+                match (*rolesdb_lock).get(&usr.to_lowercase()) {
+                    Some(usrroles)
+                        if usrroles
+                            .read()
+                            .await
+                            .contains(&UserRole::VIP(channelname.clone())) =>
+                    {
+                        // Do nothing when theh have a VIP badge and have VIP badge for the channel
+                        botlog::trace(
+                            "Already a VIP in roles",
+                            Some("identity.rs > can_user_run()".to_string()),
+                            None,
+                        );
+                    }
+
+                    _ => {
+                        // In the event they have a VIP badge , are running a bot command, but don't have a channel mod role yet...
+
+                        let mut rolesdb_lock_mut = rolesdb_lock;
+                        let usrroles = rolesdb_lock_mut.get_mut(&usr.to_lowercase()).unwrap();
+                        let mut usrroles_lock = usrroles.write().await;
+
+                        usrroles_lock.push(UserRole::VIP(channelname.clone()));
+
+                        rolechange = ChangeResult::Success("Auto Promoted VIP".to_string());
                     }
                 }
             }
@@ -865,7 +916,7 @@ impl IdentityManager {
             None,
         );
 
-        if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) {
+        if cmdreqroles.contains(&UserRole::Mod(OF_CMD_CHANNEL)) {
             botlog::trace(
                 "Command requires Mod Role",
                 Some("identity.rs > can_user_run()".to_string()),
@@ -894,14 +945,14 @@ impl IdentityManager {
                         Some("identity.rs > can_user_run()".to_string()),
                         None,
                     );
-                    return (Permissible::Allow, modrolechange);
+                    return (Permissible::Allow, rolechange);
                 }
             }
         }
 
         // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
 
-            if cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) {
+        if cmdreqroles.contains(&UserRole::SupMod(OF_CMD_CHANNEL)) {
             if let Some(a) = self
                 .special_roles_users
                 .read()
@@ -912,7 +963,7 @@ impl IdentityManager {
                     .await
                     .contains(&UserRole::SupMod(channelname.clone()))
                 {
-                    return (Permissible::Allow, modrolechange);
+                    return (Permissible::Allow, rolechange);
                 }
             }
         }
@@ -959,11 +1010,47 @@ impl IdentityManager {
                 );
 
                 if a.read().await.contains(&UserRole::BotAdmin) {
-                    return (Permissible::Allow, modrolechange);
+                    return (Permissible::Allow, rolechange);
                 }
             }
         }
 
+        // [x] If cmdreqroles includes UserRole::VIP and chatter has UserRole::VIP , Ok(Permissible::Allow)
+
+        if cmdreqroles.contains(&UserRole::VIP(OF_CMD_CHANNEL)) {
+
+            botlog::trace(
+                "Command requires VIP Role",
+                Some("identity.rs > can_user_run()".to_string()),
+                None,
+            );
+
+            if let Some(a) = self
+                .special_roles_users
+                .read()
+                .await
+                .get(&usr.to_lowercase())
+            {
+                botlog::trace(
+                    "Special roles found for user",
+                    Some("identity.rs > can_user_run()".to_string()),
+                    None,
+                );
+
+                if a.read().await.contains(&UserRole::VIP(channelname.clone()))
+                {
+                    botlog::trace(
+                        "> Special Role Identified : VIP ",
+                        Some("identity.rs > can_user_run()".to_string()),
+                        None,
+                    );
+                    return (Permissible::Allow, rolechange);
+                }
+            }
+
+        }
+
+
         (
             Permissible::Block,
             ChangeResult::NoChange("Not any permissiable condition".to_string()),
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 58d0c59..dd3cba4 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -10,6 +10,10 @@
 
 */
 
+
+const OF_CMD_CHANNEL:Channel = Channel(String::new());
+
+
 use rand::Rng;
 use std::sync::Arc;
 
@@ -26,8 +30,6 @@ use tokio::time::{sleep, Duration};
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:Channel = Channel(String::new());
-
     // 1. Define the BotAction
     let botc1 = BotCommand {
         module: BotModule(String::from("experiments001")),
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index 3be88ac..a4ecb25 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -10,6 +10,10 @@
 
 */
 
+
+const OF_CMD_CHANNEL:Channel = Channel(String::new());
+
+
 use std::sync::Arc;
 
 use chrono::{TimeZone,Local};
@@ -28,8 +32,6 @@ use crate::core::identity::UserRole::*;
 
 pub async fn init(mgr: Arc<ModulesManager>) {
 
-    const OF_CMD_CHANNEL:Channel = Channel(String::new());
-
 
     // 1. Define the BotAction
     let botc1 = BotCommand {
@@ -42,7 +44,8 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         help: String::from("Test Command tester"),
         required_roles: vec![
             BotAdmin,
-            Mod(OF_CMD_CHANNEL),
+            // Mod(OF_CMD_CHANNEL),
+            VIP(OF_CMD_CHANNEL),
         ], 
     };
 

From a6628a62a49297b7f70fe54de31928f080da8c20 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 19:33:24 -0400
Subject: [PATCH 64/98] demote/promote vip

---
 src/core/identity.rs | 212 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 183 insertions(+), 29 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 5f9a1d0..413ac3a 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -101,9 +101,14 @@ pub async fn init(mgr: Arc<ModulesManager>) {
         Usage :
 
             promote <user>
+            promote -m <user>
+            promote -mod <user>
 
             demote <user>
 
+            promote -v <user>
+            promote -vip <user>
+
             promote -admin <user>
 
          */
@@ -149,7 +154,15 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         // [x] 1. Get trgusr (regardless of -admin flag)
 
-        let targetusr = if arg1 == Some("-admin") { arg2 } else { arg1 };
+        // 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
 
@@ -166,13 +179,35 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                     Some("identity.rs > cmd_promote()".to_string()),
                     None,
                 );
+
                 Log::flush();
 
-                let target_bot_admin_role = if arg1 == Some("-admin") {
-                    Some(UserRole::BotAdmin)
-                } else {
-                    None
-                };
+
+                // // 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(
@@ -180,7 +215,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         &sender_badge,
                         targetusr.to_string(),
                         Some(Channel(targetchnl.clone())),
-                        target_bot_admin_role,
+                        target_role,
                     )
                     .await
             }
@@ -279,13 +314,21 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
             demote <user>
 
-            promote -admin <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 (arg1, arg2) = {
             let mut argv = params.msg.message_text.split(' ');
 
             argv.next(); // Skip the command name
@@ -341,10 +384,29 @@ pub async fn init(mgr: Arc<ModulesManager>) {
 
         let sender_badge = sender_badge_mut;
 
-        let targetusr = arg1;
-
+       
         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()
@@ -376,6 +438,7 @@ pub async fn init(mgr: Arc<ModulesManager>) {
                         &sender_badge,
                         targetusr.to_string(),
                         Some(Channel(targetchnl.clone())),
+                        target_role,
                     )
                     .await
             }
@@ -800,13 +863,15 @@ impl IdentityManager {
         let mut rolechange = ChangeResult::NoChange("".to_string());
 
         match chat_badge {
-            // [x] If chatBadge::Broadcaster  ...
-            // [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow)
-            // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("")  , Ok(Permissible::Allow)
+
+            // If ChatBadge::Broadcaster is observed, 
+            // Check if cmdreqroles contains Channel Level Roles . Broadcaster should have Permissible::Allow for any of these
+
             Some(ChatBadge::Broadcaster) => {
                 if cmdreqroles.contains(&UserRole::Broadcaster)
-                    || cmdreqroles.contains(&UserRole::Mod(OF_CMD_CHANNEL))
-                    || cmdreqroles.contains(&UserRole::SupMod(OF_CMD_CHANNEL))
+                || cmdreqroles.contains(&UserRole::Mod(OF_CMD_CHANNEL))
+                || cmdreqroles.contains(&UserRole::SupMod(OF_CMD_CHANNEL))
+                || cmdreqroles.contains(&UserRole::VIP(OF_CMD_CHANNEL))
                 {
                     // return Ok(Permissible::Allow)
                     return (
@@ -1075,20 +1140,27 @@ impl IdentityManager {
         Log::flush();
 
         /*
+
+        
+            // [x] => 03.25 - Q. Would there need to be extra handling here for VIP?
+
+
             [x] 1. Check if Authorizer Mod Badge then Auto Promote to Mod if not Mod
             [x] 2. Get Authorizer & Target Chatter Roles with a Given Channel
             [x] 3. If the authorizer & Target Chatters are the same, and the Authorizer is not a Admin, return no change
             [x] 4a. If Authorizer is BotAdmin & trg_role is Some(BotAdmin) , set Target as BotAdmin and return
-            [x] 4b. If target is Broadcaster, return NoChange
-            [ ] 4c. If Authorizer is a SupMod,Broadcaster,BotAdmin , can Promote Target Chatter > Mod
+            [x] 4b. If Authorizer is a Mod,SupMod,Broadcaster & trg_role is Some(VIP(channel)), can Promote a Target Chatter > VIP
+            [x] 4c. If target is Broadcaster, return NoChange
+            [x] 4d. If Authorizer is a SupMod,Broadcaster,BotAdmin , can Promote Target Chatter > Mod
                 - NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod
-            [ ] 4d. If Authorizer is a Broadcaster,BotAdmin , can Promote a Target Mod > SupMod
+            [x] 4e. If Authorizer is a Broadcaster,BotAdmin , can Promote a Target Mod > SupMod
                 - NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod
 
 
+
         */
 
-        // [x] 1. Check if Authorizer Mod Badge then Auto Promote to Mod if not Mod
+        // [x] 1. Check if Authorizer Mod or VIP Badge then Auto Promote to matching UserRole if not already assigned
 
         let trgchatter = trgchatter.to_lowercase();
 
@@ -1110,10 +1182,23 @@ impl IdentityManager {
                             .await;
                     }
 
+                    
+                    // [x] - May want to Auto VIP Authorizer here
+                    Some(ChatBadge::VIP)
+                        if (!authusrroles.contains(&UserRole::VIP(channel.clone()))) =>
+                    {
+                        authusrroles.push(UserRole::VIP(channel.clone()));
+
+                        self.affirm_chatter_in_db(authorizer.clone()).await;
+                        self.add_role(authorizer.clone(), UserRole::VIP(channel.clone()))
+                            .await;
+                    } 
+
                     _ => (),
                 }
             }
 
+
             // [x] 2. Get Authorizer & Target Chatter Roles
 
             let trgusrroles = self
@@ -1131,7 +1216,6 @@ impl IdentityManager {
 
             (authusrroles, trgusrroles)
         };
-
         //  [x] 3. If the authorizer & Target Chatters are the same, and the Authorizer is not a Admin, return no change
         if trgchatter == authorizer && !authusrroles.contains(&UserRole::BotAdmin) {
             return ChangeResult::NoChange("Can't target yourself".to_string());
@@ -1150,20 +1234,47 @@ impl IdentityManager {
             }
         }
 
-        // [x] 4b. If target is Broadcaster, return NoChange
+        // [x] 4b. If Authorizer is a Mod,SupMod,Broadcaster & trg_role is Some(VIP(channel)), can Promote a Target Chatter > VIP
+        if let Some(trg_chnl) = channel.clone() {
+            if ( authusrroles.contains(&UserRole::Mod(trg_chnl.clone()))
+            || authusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
+            || authusrroles.contains(&UserRole::Broadcaster)
+            ) 
+            && trg_role == Some(UserRole::VIP(trg_chnl.clone())) {
+                if trgusrroles.contains(&UserRole::VIP(trg_chnl.clone())) {
+                    return ChangeResult::NoChange("Already has the role".to_string());
+                } 
+                else {
+                    self.affirm_chatter_in_db(trgchatter.clone()).await;
+
+                    self.add_role(trgchatter.clone(), UserRole::VIP(trg_chnl.clone())).await;
+
+                    return ChangeResult::Success("Promotion Successful".to_string());
+                }
+            }
+        }
+
+
+        
+
+
+        // [x] 4c. If target is Broadcaster, return NoChange
 
         if trgusrroles.contains(&UserRole::Broadcaster) {
             return ChangeResult::NoChange("Can't target broadcaster".to_string());
         }
 
+        
         /*
-           [ ] 4c. If Authorizer is a SupMod,Broadcaster,BotAdmin , can Promote Target Chatter > Mod
+           [x] 4d. If Authorizer is a SupMod,Broadcaster,BotAdmin , can Promote Target Chatter > Mod
                - NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod
-           [ ] 4d. If Authorizer is a Broadcaster,BotAdmin , can Promote a Target Mod > SupMod
+           [x] 4e. If Authorizer is a Broadcaster,BotAdmin , can Promote a Target Mod > SupMod
                - NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod
         */
 
         if let Some(trg_chnl) = channel.clone() {
+
+            // 1. Checks first if Target User's Roles do not Include Broadcaster,Mod,SupMod for the Channel
             if !trgusrroles.contains(&UserRole::Broadcaster)
                 && !trgusrroles.contains(&UserRole::Mod(trg_chnl.clone()))
                 && !trgusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
@@ -1172,6 +1283,8 @@ impl IdentityManager {
                 // target's Next Role would be Mod
                 // Authorizer must be SupMod,Broadcaster,BotAdmin
                 // > Promote target to Mod
+
+                // 2. If Authorizer has Elevated Admin Roles for the Channel (SupMod,Broadcaster,BotAdmin) > set target to MOD
                 if authusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
                     || authusrroles.contains(&UserRole::Broadcaster)
                     || authusrroles.contains(&UserRole::BotAdmin)
@@ -1233,6 +1346,8 @@ impl IdentityManager {
             }
         };
 
+
+
         botlog::warn(
             "Runtime reached undeveloped code",
             Some("identity.rs > promote()".to_string()),
@@ -1247,6 +1362,7 @@ impl IdentityManager {
         authorizer_badge: &Option<ChatBadge>,
         trgchatter: String,
         channel: Option<Channel>,
+        trg_role: Option<UserRole>,
     ) -> ChangeResult {
         botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?}",
                     authorizer,trgchatter,channel), Some("identity.rs > demote()".to_string()), None);
@@ -1260,7 +1376,7 @@ impl IdentityManager {
            Use the roles of the above to determine whether the authorizer can demote the target user or not
         */
 
-        // [x] 1. If Authorizer's Badge is Mod, ensuring Sender is in DB as Mod(Channel)
+        // [x] 1. If Authorizer's Badge is Mod/VIP, ensuring Sender is in DB as Mod(Channel)
 
         let trgchatter = trgchatter.to_lowercase();
 
@@ -1283,6 +1399,17 @@ impl IdentityManager {
                         self.add_role(authorizer.clone(), UserRole::Mod(channel.clone()))
                             .await;
                     }
+                    // [x] - May want to Auto VIP Authorizer here
+                    Some(ChatBadge::VIP)
+                        if (!authusrroles.contains(&UserRole::VIP(channel.clone()))) =>
+                    {
+                        authusrroles.push(UserRole::VIP(channel.clone()));
+
+                        self.affirm_chatter_in_db(authorizer.clone()).await;
+                        self.add_role(authorizer.clone(), UserRole::VIP(channel.clone()))
+                            .await;
+                    } 
+                
                     _ => (),
                 }
             }
@@ -1298,7 +1425,30 @@ impl IdentityManager {
                 return ChangeResult::NoChange("Can't target yourself".to_string());
             }
 
-            // [x] 4a. Authorizers who are BotAdmin, Broadcaster or Supermod can demote a Mod
+            // [x] 4. If Authorizer is a Mod,SupMod,Broadcaster & trg_role is Some(VIP(channel)), can Promote a Target Chatter > VIP
+
+            if ( authusrroles.contains(&UserRole::Mod(channel.clone()))
+            || authusrroles.contains(&UserRole::SupMod(channel.clone()))
+            || authusrroles.contains(&UserRole::Broadcaster)
+            ) 
+            && trg_role == Some(UserRole::VIP(channel.clone())) {
+                if trgusrroles.contains(&UserRole::VIP(channel.clone())) {
+                    return ChangeResult::NoChange("Already has the role".to_string());
+                } 
+                else {
+                    self.affirm_chatter_in_db(trgchatter.clone()).await;
+
+                    self.add_role(trgchatter.clone(), UserRole::VIP(channel.clone())).await;
+
+                    return ChangeResult::Success("Promotion Successful".to_string());
+                }
+            }
+
+
+            // [x] 5. - Mod/SupMod Logic
+
+
+            // [x] 5a. Authorizers who are BotAdmin, Broadcaster or Supermod can demote a Mod
 
             if (authusrroles.contains(&UserRole::BotAdmin)
                 || authusrroles.contains(&UserRole::Broadcaster)
@@ -1309,7 +1459,7 @@ impl IdentityManager {
                     .await;
                 return ChangeResult::Success("Demoted successfully".to_string());
             }
-            // [x] 4b. Authorizers who are BotAdmin, Broadcaster can demote a SupMod
+            // [x] 5b. Authorizers who are BotAdmin, Broadcaster can demote a SupMod
             else if (authusrroles.contains(&UserRole::BotAdmin)
                 || authusrroles.contains(&UserRole::Broadcaster))
                 && trgusrroles.contains(&UserRole::SupMod(channel.clone()))
@@ -1320,7 +1470,7 @@ impl IdentityManager {
                     .await;
                 return ChangeResult::Success("Demoted successfully".to_string());
             }
-            // [x] 4c. When Target chatter isnt a Mod or SupMod to demote
+            // [x] 5c. When Target chatter isnt a Mod or SupMod to demote
             else if !trgusrroles.contains(&UserRole::Mod(channel.clone()))
                 && !trgusrroles.contains(&UserRole::SupMod(channel.clone()))
             {
@@ -1328,7 +1478,7 @@ impl IdentityManager {
                     "Target chatter does not have a role that can be demoted".to_string(),
                 );
             }
-            // [x] 4d. When they're only a Mod
+            // [x] 5d. When they're only a Mod
             else if authusrroles.contains(&UserRole::Mod(channel.clone())) {
                 return ChangeResult::Failed("You're not permitted to do that".to_string());
             }
@@ -1833,6 +1983,7 @@ mod core_identity {
         let authorizer = regmod.clone();
         let authorizer_badge = &None;
         let trgchatter = supmod.clone();
+        let trg_role = None;
 
         let rslt = test_id_mgr
             .demote(
@@ -1840,6 +1991,7 @@ mod core_identity {
                 authorizer_badge,
                 trgchatter.clone(),
                 channel.clone(),
+                trg_role.clone(),
             )
             .await;
 
@@ -1860,6 +2012,7 @@ mod core_identity {
                 authorizer_badge,
                 trgchatter.clone(),
                 channel.clone(),
+                trg_role.clone(),
             )
             .await;
 
@@ -1874,6 +2027,7 @@ mod core_identity {
                 authorizer_badge,
                 trgchatter.clone(),
                 channel.clone(),
+                trg_role.clone(),
             )
             .await;
 

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 65/98] 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,

From df6fe8ccb757e2e6eb9129ab09a4c2c2893cabab Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 20:11:50 -0400
Subject: [PATCH 66/98] refined promote/demote

---
 src/core/identity.rs | 34 +++++++++++++++++++++++++++-------
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 7ad804b..35a2c07 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -1779,13 +1779,22 @@ impl IdentityManager {
             }
         }
 
+        botlog::debug(
+            format!("VIP Evaluation : Channel = {:?} ; trg_role = {:?} ",
+                    channel.clone(),trg_role
+            ).as_str(),
+            Some("identity.rs > promote()".to_string()),
+            None,
+        );
+
         // [x] 4b. If Authorizer is a Mod,SupMod,Broadcaster & trg_role is Some(VIP(channel)), can Promote a Target Chatter > VIP
         if let Some(trg_chnl) = channel.clone() {
-            if ( authusrroles.contains(&UserRole::Mod(trg_chnl.clone()))
+            if trg_role == Some(UserRole::VIP(trg_chnl.clone())) 
+            && ( authusrroles.contains(&UserRole::Mod(trg_chnl.clone()))
             || authusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
             || authusrroles.contains(&UserRole::Broadcaster)
             ) 
-            && trg_role == Some(UserRole::VIP(trg_chnl.clone())) {
+            {
                 if trgusrroles.contains(&UserRole::VIP(trg_chnl.clone())) {
                     return ChangeResult::NoChange("Already has the role".to_string());
                 } 
@@ -1796,6 +1805,9 @@ impl IdentityManager {
 
                     return ChangeResult::Success("Promotion Successful".to_string());
                 }
+            } else if trg_role == Some(UserRole::VIP(trg_chnl.clone())) 
+            {
+                return ChangeResult::Failed(String::from("You're not permitted to do that"));
             }
         }
 
@@ -1977,15 +1989,15 @@ impl IdentityManager {
             || authusrroles.contains(&UserRole::Broadcaster)
             ) 
             && trg_role == Some(UserRole::VIP(channel.clone())) {
-                if trgusrroles.contains(&UserRole::VIP(channel.clone())) {
-                    return ChangeResult::NoChange("Already has the role".to_string());
+                if !trgusrroles.contains(&UserRole::VIP(channel.clone())) {
+                    return ChangeResult::NoChange("Already does not haev VIP role".to_string());
                 } 
                 else {
-                    self.affirm_chatter_in_db(trgchatter.clone()).await;
+                    // self.affirm_chatter_in_db(trgchatter.clone()).await;
 
-                    self.add_role(trgchatter.clone(), UserRole::VIP(channel.clone())).await;
+                    self.remove_role(trgchatter.clone(), UserRole::VIP(channel.clone())).await;
 
-                    return ChangeResult::Success("Promotion Successful".to_string());
+                    return ChangeResult::Success("Demotion Successful".to_string());
                 }
             }
 
@@ -2040,6 +2052,11 @@ impl IdentityManager {
         chattername: String,
         channel: Option<Channel>,
     ) -> Vec<UserRole> {
+        /*
+            NOTE : Any NEW or CHANGES to UserRole type should have additional handling here
+                Specifically for Channel Elevated Roles
+         */
+
         /*
            Note : Ideally this be called for a given chatter name ?
         */
@@ -2109,6 +2126,9 @@ impl IdentityManager {
                         if a.read().await.contains(&UserRole::SupMod(channel.clone())) {
                             evalsproles.push(UserRole::SupMod(channel.clone()));
                         }
+                        if a.read().await.contains(&UserRole::VIP(channel.clone())) {
+                            evalsproles.push(UserRole::VIP(channel.clone()));
+                        }
                         // else {};
                     }
                     None => {

From e66985814a717809e31dd751728211496766330b Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 20:24:05 -0400
Subject: [PATCH 67/98] promote/demote checks invalid arg flag

---
 src/core/identity.rs | 49 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 11 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 35a2c07..1252693 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -732,6 +732,13 @@ async fn cmd_promote(params : ExecBodyParams) {
 
     */
 
+    
+
+    let botlock = params.bot.read().await;
+    let id = botlock.get_identity();
+    let idlock = id.read().await;
+
+
     // [x] 1. Get trgusr (regardless of -admin flag)
 
     // let targetusr = if arg1 == Some("-admin") { arg2 } else { arg1 };
@@ -742,16 +749,22 @@ async fn cmd_promote(params : ExecBodyParams) {
             || arg1 == Some("-m") 
             || arg1 == Some("-mod") 
             { arg2 } 
+            else if let Some(a) = arg1 {
+                if a.starts_with("-") {
+                    botlock.botmgrs.chat.send_botmsg(
+                    super::chat::BotMsgType::Notif(
+                        "Invalid Argument Flag".to_string()
+                        ),
+                    params.clone(),
+                    ).await;
+                    return 
+                } else { arg1 }
+            }
             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(
@@ -934,6 +947,15 @@ async fn cmd_demote(params : ExecBodyParams) {
 
      */
 
+    
+
+    // [x] Get a required lock first
+
+    let botlock = params.bot.read().await;
+    let id = botlock.get_identity();
+    let idlock = id.read().await;
+
+
     let sendername = params.msg.clone().sender.name;
 
     let mut sender_badge_mut: Option<ChatBadge> = None;
@@ -961,6 +983,17 @@ async fn cmd_demote(params : ExecBodyParams) {
         || arg1 == Some("-m") 
         || arg1 == Some("-mod") 
         { arg2 } 
+            else if let Some(a) = arg1 {
+                if a.starts_with("-") {
+                    botlock.botmgrs.chat.send_botmsg(
+                    super::chat::BotMsgType::Notif(
+                        "Invalid Argument Flag".to_string()
+                        ),
+                    params.clone(),
+                    ).await;
+                    return 
+                } else { arg1 }
+            }
         else { arg1 };
 
     // Note : At the moment, no handling of -admin
@@ -983,12 +1016,6 @@ async fn cmd_demote(params : ExecBodyParams) {
 
      */
 
-    // [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(

From feff709714a9a2d1f234513ee3064588cc0003cd Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 21:26:32 -0400
Subject: [PATCH 68/98] unit tests

---
 src/core/botinstance.rs |   9 ++
 src/core/identity.rs    | 215 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 221 insertions(+), 3 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index e9d83cf..e7dd889 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -37,6 +37,15 @@ pub enum ChangeResult {
 
 pub struct Channel(pub String);
 
+// impl PartialEq for Channel {
+//     fn eq(&self, other: &Self) -> bool {
+//         let Channel(name1) = self.clone();
+//         let Channel(name2) = other.clone();
+//         name1.to_lowercase() == name2.to_lowercase()
+//     }
+// }
+// impl Eq for Channel {}
+
 use super::bot_actions::ExecBodyParams;
 use super::botmodules::StatusType;
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index 1252693..fa74e92 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -2017,7 +2017,7 @@ impl IdentityManager {
             ) 
             && trg_role == Some(UserRole::VIP(channel.clone())) {
                 if !trgusrroles.contains(&UserRole::VIP(channel.clone())) {
-                    return ChangeResult::NoChange("Already does not haev VIP role".to_string());
+                    return ChangeResult::NoChange("Already does not have VIP role".to_string());
                 } 
                 else {
                     // self.affirm_chatter_in_db(trgchatter.clone()).await;
@@ -2108,7 +2108,8 @@ impl IdentityManager {
             Some(chnl) => {
                 // In this block, Some input channel is given
                 // We're comparing the channel name with chattername to determine if they're a broadcaster
-                if chattername == chnl.0 
+                // if chattername == chnl.0 
+                if chattername == chnl.0.to_lowercase() 
                 {
                     evalsproles.push(UserRole::Broadcaster);
                 }
@@ -2193,7 +2194,7 @@ impl IdentityManager {
 #[cfg(test)]
 mod core_identity {
 
-    use casual_logger::Extension;
+    use casual_logger::{Extension, Level};
 
     use super::*;
 
@@ -2630,4 +2631,212 @@ mod core_identity {
             )
         );
     }
+
+
+
+    #[tokio::test]
+    async fn vip_workflow_01() {
+        Log::set_file_ext(Extension::Log);
+        //Log::set_level(Level::Trace);        
+
+        // Channel Elevated User Promotes/Demotes VIP
+
+        let test_id_mgr = IdentityManager::init();
+
+
+        
+        // [x] 1. Requester has a Mod Role
+
+        let channel = Some(Channel("somechannel".to_string()));
+        let authorizer_badge = &Some(ChatBadge::Mod);
+        let authorizer = "chatMod".to_string();
+        let trgchatter = "regularChatter".to_string();
+        let trg_role = Some(UserRole::VIP(channel.clone().unwrap()));
+
+        let authorizer = authorizer.to_lowercase();
+        let trgchatter = trgchatter.to_lowercase();
+
+        test_id_mgr.affirm_chatter_in_db(authorizer.clone()).await;
+        test_id_mgr.affirm_chatter_in_db(trgchatter.clone()).await;
+
+        test_id_mgr
+            .add_role(authorizer.clone(), UserRole::Mod(channel.clone().unwrap()))
+            .await;
+
+        let rslt = test_id_mgr
+            .getspecialuserroles(authorizer.clone(), channel.clone())
+            .await;
+
+        assert_eq!(rslt,vec![UserRole::Mod(channel.clone().unwrap())]);
+
+        // [x] 2. assert getspecialuserroles for Target Chatter
+
+        let rslt = test_id_mgr
+            .getspecialuserroles(trgchatter.clone(), channel.clone())
+            .await;
+
+        assert_eq!(rslt,vec![]);
+
+        // [x] 3. Requester Promotes a Target Chatter to VIP
+
+        let rslt = test_id_mgr
+            .promote(
+                authorizer.clone(),
+                authorizer_badge,
+                trgchatter.clone(),
+                channel.clone(),
+                trg_role.clone(),
+            )
+            .await;
+
+        assert_eq!(
+            rslt,
+            ChangeResult::Success("Promotion Successful".to_string())
+        );
+
+
+        // [x] 4. assert getspecialuserroles for Target Chatter
+
+        let rslt = test_id_mgr
+            .getspecialuserroles(trgchatter.clone(), channel.clone())
+            .await;
+
+        assert!(rslt.contains(&UserRole::VIP(channel.clone().unwrap())));
+
+        // [x] 5. Requester Promotes a Target Chatter to VIP
+        
+        let rslt = test_id_mgr
+            .promote(
+                authorizer.clone(),
+                authorizer_badge,
+                trgchatter.clone(),
+                channel.clone(),
+                trg_role.clone(),
+            )
+            .await;
+
+        assert_eq!(
+            rslt,
+            ChangeResult::NoChange("Already has the role".to_string())
+        );
+
+
+        // [x] 6. assert getspecialuserroles for Target Chatter
+        
+        let rslt = test_id_mgr
+            .getspecialuserroles(trgchatter.clone(), channel.clone())
+            .await;
+
+        assert!(rslt.contains(&UserRole::VIP(channel.clone().unwrap())));
+
+
+        // [x] 7. Requester Demotes a Target Chatter from VIP
+
+        let rslt = test_id_mgr
+        .demote(
+            authorizer.clone(),
+            authorizer_badge,
+            trgchatter.clone(),
+            channel.clone(),
+            trg_role.clone(),
+        )
+        .await;
+
+        assert_eq!(
+            rslt,
+            ChangeResult::Success("Demotion Successful".to_string())
+        );
+
+        // [x] 8. assert getspecialuserroles for Target Chatter
+
+        let rslt = test_id_mgr
+            .getspecialuserroles(trgchatter.clone(), channel.clone())
+            .await;
+
+        // assert!(rslt.contains(&UserRole::VIP(channel.clone().unwrap())));
+        assert_eq!(rslt,vec![]);
+
+
+   
+        // [x] 9. Requester Demotes a Target Chatter from VIP
+
+        let rslt = test_id_mgr
+        .demote(
+            authorizer.clone(),
+            authorizer_badge,
+            trgchatter.clone(),
+            channel.clone(),
+            trg_role.clone(),
+        )
+        .await;
+
+        assert_eq!(
+            rslt,
+            ChangeResult::NoChange("Already does not have VIP role".to_string())
+        );
+
+        // [x] 10. assert getspecialuserroles for Target Chatter
+
+        let rslt = test_id_mgr
+            .getspecialuserroles(trgchatter.clone(), channel.clone())
+            .await;
+
+        assert_eq!(rslt,vec![]);
+
+
+   
+
+
+    }
+
+
+    #[tokio::test]
+    async fn auto_vip_workflow() {
+        Log::set_file_ext(Extension::Log);
+
+        let mut test_id_mgr = IdentityManager::init();
+
+
+
+        let channel = Some(Channel("somechannel".to_string()));
+        let authorizer_badge = Some(ChatBadge::VIP);
+        let authorizer = "chatMod".to_string();
+
+        let authorizer = authorizer.to_lowercase();
+
+
+        // [x] 1. assert getspecialuserroles for Target Chatter
+
+        let rslt = test_id_mgr
+        .getspecialuserroles(authorizer.clone(), channel.clone())
+        .await;
+
+        assert_eq!(rslt,vec![]);
+
+        // [x] 2. Run canuserrun() for the Requester . (This is ran after BotCommands are ran)
+
+        let rslt = test_id_mgr
+        .can_user_run(
+            authorizer.clone(), 
+            channel.clone().unwrap(), 
+            authorizer_badge, 
+            vec![            
+                UserRole::VIP(OF_CMD_CHANNEL),
+            ]
+        ).await;
+
+        assert_eq!(rslt,
+            (Permissible::Allow,ChangeResult::Success("Auto Promoted VIP".to_string())));
+
+        // [x] 3. assert getspecialuserroles for Target Chatter
+
+        let rslt = test_id_mgr
+            .getspecialuserroles(authorizer.clone(), channel.clone())
+            .await;
+
+        assert_eq!(rslt,vec![UserRole::VIP(channel.unwrap())]);
+
+    
+
+    }
 }

From de2ef03661e05e3c950374e4d6950f348122271f Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Mon, 25 Mar 2024 21:50:39 -0400
Subject: [PATCH 69/98] clippy & comments cleanup

---
 src/core/botinstance.rs |  24 +-
 src/core/identity.rs    | 576 +---------------------------------------
 2 files changed, 13 insertions(+), 587 deletions(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index e7dd889..07b481d 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -37,15 +37,6 @@ pub enum ChangeResult {
 
 pub struct Channel(pub String);
 
-// impl PartialEq for Channel {
-//     fn eq(&self, other: &Self) -> bool {
-//         let Channel(name1) = self.clone();
-//         let Channel(name2) = other.clone();
-//         name1.to_lowercase() == name2.to_lowercase()
-//     }
-// }
-// impl Eq for Channel {}
-
 use super::bot_actions::ExecBodyParams;
 use super::botmodules::StatusType;
 
@@ -480,13 +471,6 @@ impl BotInstance {
                                     params.clone(),
                                     ).await;
 
-
-                                    // botlock.botmgrs.chat.say_in_reply_to(
-                                    //     msg, 
-                                    //     outstr,
-                                    //     // c.module.clone(),
-                                    //     params
-                                    // ).await;
                                 }
 
                                 if innerstr
@@ -516,13 +500,7 @@ impl BotInstance {
                                         ),
                                     params.clone(),
                                     ).await;
-
-                                    // botlock.botmgrs.chat.say_in_reply_to(
-                                    //     msg, 
-                                    //     outstr,
-                                    //     // c.module.clone(),
-                                    //     params
-                                    // ).await;
+                                    
                                 }
                             }
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index fa74e92..dc2da72 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -74,200 +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",
-            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,
-        );
-    }
-*/
+    
     let tempb = BotCommand {
         module: BotModule(String::from("identity")),
         command: String::from("demote"), // command call name
@@ -283,211 +90,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",
-            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;
-
-
-    }
-*/
+    
     let tempcomm = BotCommand {
         module: BotModule(String::from("identity")),
         command: String::from("getroles"), // command call name
@@ -503,147 +106,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",
-            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
-    }
-*/
+    
     botlog::trace(
         "End of Init MOdule add",
         Some("identity.rs > init ".to_string()),
@@ -750,7 +213,7 @@ async fn cmd_promote(params : ExecBodyParams) {
             || arg1 == Some("-mod") 
             { arg2 } 
             else if let Some(a) = arg1 {
-                if a.starts_with("-") {
+                if a.starts_with('-') {
                     botlock.botmgrs.chat.send_botmsg(
                     super::chat::BotMsgType::Notif(
                         "Invalid Argument Flag".to_string()
@@ -777,13 +240,6 @@ async fn cmd_promote(params : ExecBodyParams) {
 
 
             // // 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)
@@ -793,15 +249,6 @@ async fn cmd_promote(params : ExecBodyParams) {
                     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(),
@@ -984,7 +431,7 @@ async fn cmd_demote(params : ExecBodyParams) {
         || arg1 == Some("-mod") 
         { arg2 } 
             else if let Some(a) = arg1 {
-                if a.starts_with("-") {
+                if a.starts_with('-') {
                     botlock.botmgrs.chat.send_botmsg(
                     super::chat::BotMsgType::Notif(
                         "Invalid Argument Flag".to_string()
@@ -2194,7 +1641,7 @@ impl IdentityManager {
 #[cfg(test)]
 mod core_identity {
 
-    use casual_logger::{Extension, Level};
+    use casual_logger::Extension;
 
     use super::*;
 
@@ -2798,7 +2245,8 @@ mod core_identity {
 
 
 
-        let channel = Some(Channel("somechannel".to_string()));
+        // let channel = Some(Channel("somechannel".to_string()));
+        let channel = Channel("somechannel".to_string());
         let authorizer_badge = Some(ChatBadge::VIP);
         let authorizer = "chatMod".to_string();
 
@@ -2808,7 +2256,7 @@ mod core_identity {
         // [x] 1. assert getspecialuserroles for Target Chatter
 
         let rslt = test_id_mgr
-        .getspecialuserroles(authorizer.clone(), channel.clone())
+        .getspecialuserroles(authorizer.clone(), Some(channel.clone()))
         .await;
 
         assert_eq!(rslt,vec![]);
@@ -2818,7 +2266,7 @@ mod core_identity {
         let rslt = test_id_mgr
         .can_user_run(
             authorizer.clone(), 
-            channel.clone().unwrap(), 
+            channel.clone(), 
             authorizer_badge, 
             vec![            
                 UserRole::VIP(OF_CMD_CHANNEL),
@@ -2831,10 +2279,10 @@ mod core_identity {
         // [x] 3. assert getspecialuserroles for Target Chatter
 
         let rslt = test_id_mgr
-            .getspecialuserroles(authorizer.clone(), channel.clone())
+            .getspecialuserroles(authorizer.clone(), Some(channel.clone()))
             .await;
 
-        assert_eq!(rslt,vec![UserRole::VIP(channel.unwrap())]);
+        assert_eq!(rslt,vec![UserRole::VIP(channel)]);
 
     
 

From 95a9962721c53c4a199434333f22b279cec87766 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Thu, 28 Mar 2024 15:38:49 -0300
Subject: [PATCH 70/98] new module test

trying to add a new module
---
 src/custom/experimental/experiment001.rs |  4 --
 src/lib.rs                               |  1 +
 src/modules.rs                           | 10 ++++
 src/modules/test.rs                      | 17 ++++++
 src/modules/thisguy.rs                   | 68 ++++++++++++++++++++++++
 5 files changed, 96 insertions(+), 4 deletions(-)
 create mode 100644 src/modules.rs
 create mode 100644 src/modules/test.rs
 create mode 100644 src/modules/thisguy.rs

diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index dd3cba4..28d499b 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -122,8 +122,6 @@ async fn good_girl(params : ExecBodyParams) {
             );
 
             let bot = Arc::clone(&params.bot);
-
-
             let botlock = bot.read().await;
 
             // uses chat.say_in_reply_to() for the bot controls for messages
@@ -135,8 +133,6 @@ async fn good_girl(params : ExecBodyParams) {
                 String::from("GoodGirl xdd "),
                 params.clone()
             ).await;
-
-
         }
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index c5ba775..f01fd10 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,2 +1,3 @@
 pub mod core;
 pub mod custom;
+pub mod modules;
\ No newline at end of file
diff --git a/src/modules.rs b/src/modules.rs
new file mode 100644
index 0000000..d0b1c6e
--- /dev/null
+++ b/src/modules.rs
@@ -0,0 +1,10 @@
+use std::sync::Arc;
+pub use crate::core::botinstance::BotInstance;
+pub use crate::core::botmodules::ModulesManager;
+
+
+mod thisguy;
+
+pub async fn init(mgr:&Arc<ModulesManager>){
+    thisguy::init(mgr).await;
+}
\ No newline at end of file
diff --git a/src/modules/test.rs b/src/modules/test.rs
new file mode 100644
index 0000000..ba7d68d
--- /dev/null
+++ b/src/modules/test.rs
@@ -0,0 +1,17 @@
+use std::sync::Arc;
+
+// pub use crate::core::botinstance::BotInstance;
+pub use crate::core::botmodules::ModulesManager;
+
+// [ ] Load submodules
+
+mod thisguy;
+
+// [ ] init() function that accepts bot instance - this is passed to init() on submodules
+
+pub async fn init(mgr: Arc<ModulesManager>) {
+    // Modules initializer loads modules into the bot
+    // this is achieved by calling submodules that also have fn init() defined
+
+    thisguy::init(Arc::clone(&mgr)).await;
+}
diff --git a/src/modules/thisguy.rs b/src/modules/thisguy.rs
new file mode 100644
index 0000000..339d4c4
--- /dev/null
+++ b/src/modules/thisguy.rs
@@ -0,0 +1,68 @@
+use crate::core::botmodules::{ BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
+use crate::core::identity::UserRole::*;
+use crate::core::bot_actions::*;
+use crate::core::botlog;
+use std::sync::Arc;
+use tokio::time::{sleep, Duration};
+
+
+async fn tsg(params: ExecBodyParams){
+
+    
+
+    if params.msg.sender.name.to_lowercase() == "haruyuumei".to_lowercase()
+    //|| params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
+    {
+        botlog::debug(
+            "Oh god I love anime Girls!!",
+            Some("modules > thisguy()".to_string()),
+            Some(&params.msg),
+        );
+        let bot = Arc::clone(&params.bot);
+        let botlock = bot.read().await;
+
+        // uses chat.say_in_reply_to() for the bot controls for messages
+        botlock
+        .botmgrs
+        .chat
+        .say_in_reply_to(
+            &params.msg, 
+            String::from("Oh god I love anime Girls!!"),
+            params.clone()
+        ).await;
+        sleep(Duration::from_secs_f64(0.5)).await;
+    }
+    
+}
+
+pub async fn init(mgr:&Arc<ModulesManager>){
+
+    BotCommand{
+        module:BotModule(String::from("thisguy")),
+        command: String::from("this"),
+        alias: vec![String::from("tsg")],
+        exec_body: actions_util::asyncbox(tesst),
+        help: String::from("test"),
+        required_roles: vec![
+        BotAdmin,
+        ],
+    }.add_to_modmgr(Arc::clone(&mgr)).await;
+    
+
+
+    Listener {
+        module: BotModule(String::from("thisguy")),
+        name: String::from("This Guy Listener"),
+        exec_body: actions_util::asyncbox(tsg),
+        help: String::from(""),
+    }.add_to_modmgr(Arc::clone(&mgr)).await;
+}
+
+async fn tesst(params : ExecBodyParams) {
+    println!("tesst triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
+    botlog::debug(
+        "tesst triggered!",
+        Some("modules > tesst()".to_string()),
+        Some(&params.msg),
+    );
+}

From 6a026b779186ac691f396690dd5e3ca75c118065 Mon Sep 17 00:00:00 2001
From: mzntori <44904735+ElektroEnte@users.noreply.github.com>
Date: Thu, 28 Mar 2024 20:12:51 +0100
Subject: [PATCH 71/98] reduce seconds to minutes

---
 src/core/botinstance.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs
index 07b481d..efd0f9b 100644
--- a/src/core/botinstance.rs
+++ b/src/core/botinstance.rs
@@ -122,7 +122,7 @@ impl BotInstance {
 
         tokio::spawn(async { 
             loop {
-                let routine_mins = 60 * 60 * 24 ; // Every 1 Day
+                let routine_mins = 60 * 24 ; // Every 1 Day
                 // let routine_mins = 1; // Every 1 Minute
                 Log::remove_old_logs();
                 Log::info(&format!("Internal Purge Routine Triggered - running every {} mins",routine_mins));

From f8de595290c5bfabb1e591373964e0edc85755d5 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Thu, 28 Mar 2024 18:50:28 -0300
Subject: [PATCH 72/98] custom module update

---
 src/custom.rs                            |  4 +++-
 src/custom/experimental/experiment001.rs |  1 +
 src/{modules => custom}/thisguy.rs       | 28 +++++++++++++++---------
 src/lib.rs                               |  3 +--
 src/modules.rs                           | 10 ---------
 src/modules/test.rs                      | 17 --------------
 6 files changed, 23 insertions(+), 40 deletions(-)
 rename src/{modules => custom}/thisguy.rs (73%)
 delete mode 100644 src/modules.rs
 delete mode 100644 src/modules/test.rs

diff --git a/src/custom.rs b/src/custom.rs
index 6107797..56c6257 100644
--- a/src/custom.rs
+++ b/src/custom.rs
@@ -13,6 +13,7 @@ pub use crate::core::botmodules::ModulesManager;
 
 // mod experiments;
 mod experimental;
+mod thisguy;
 
 // [ ] init() function that accepts bot instance - this is passed to init() on submodules
 
@@ -21,5 +22,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // this is achieved by calling submodules that also have fn init() defined
 
     // experiments::init(mgr).await
-    experimental::init(mgr).await;
+    experimental::init(mgr.clone()).await;
+    thisguy::init(&mgr).await;
 }
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 28d499b..92af44d 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -105,6 +105,7 @@ async fn good_girl(params : ExecBodyParams) {
 
     if params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
         || params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
+        || params.msg.sender.name.to_lowercase() == "haruyuumei".to_lowercase()
     {
         botlog::debug(
             "Good Girl Detected > Pausechamp",
diff --git a/src/modules/thisguy.rs b/src/custom/thisguy.rs
similarity index 73%
rename from src/modules/thisguy.rs
rename to src/custom/thisguy.rs
index 339d4c4..b5e895f 100644
--- a/src/modules/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -3,16 +3,26 @@ use crate::core::identity::UserRole::*;
 use crate::core::bot_actions::*;
 use crate::core::botlog;
 use std::sync::Arc;
+use rand::Rng;
 use tokio::time::{sleep, Duration};
-
+//use rand::Rng;
 
 async fn tsg(params: ExecBodyParams){
 
-    
-
     if params.msg.sender.name.to_lowercase() == "haruyuumei".to_lowercase()
-    //|| params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
+    || params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
     {
+        let phrases: [String;5] = [
+        "Aware Weebs...".to_string(),
+        "AYAYA I love anime Girls!!".to_string(),
+        "I love 2d Girls ILOST".to_string(),
+        "UOOHHHHH!!! Anime Girlssss".to_string(),
+        "Anime girls u say? peepoShy".to_string(),
+        ];
+        
+        let r = rand::thread_rng().gen_range(0..=4);
+        let a = phrases[r].clone();
+
         botlog::debug(
             "Oh god I love anime Girls!!",
             Some("modules > thisguy()".to_string()),
@@ -26,8 +36,8 @@ async fn tsg(params: ExecBodyParams){
         .botmgrs
         .chat
         .say_in_reply_to(
-            &params.msg, 
-            String::from("Oh god I love anime Girls!!"),
+            &params.msg,
+        a,
             params.clone()
         ).await;
         sleep(Duration::from_secs_f64(0.5)).await;
@@ -39,16 +49,14 @@ pub async fn init(mgr:&Arc<ModulesManager>){
 
     BotCommand{
         module:BotModule(String::from("thisguy")),
-        command: String::from("this"),
-        alias: vec![String::from("tsg")],
+        command: String::from("anime"),
+        alias: vec![String::from("Anime")],
         exec_body: actions_util::asyncbox(tesst),
         help: String::from("test"),
         required_roles: vec![
         BotAdmin,
         ],
     }.add_to_modmgr(Arc::clone(&mgr)).await;
-    
-
 
     Listener {
         module: BotModule(String::from("thisguy")),
diff --git a/src/lib.rs b/src/lib.rs
index f01fd10..667ce02 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,2 @@
 pub mod core;
-pub mod custom;
-pub mod modules;
\ No newline at end of file
+pub mod custom;
\ No newline at end of file
diff --git a/src/modules.rs b/src/modules.rs
deleted file mode 100644
index d0b1c6e..0000000
--- a/src/modules.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use std::sync::Arc;
-pub use crate::core::botinstance::BotInstance;
-pub use crate::core::botmodules::ModulesManager;
-
-
-mod thisguy;
-
-pub async fn init(mgr:&Arc<ModulesManager>){
-    thisguy::init(mgr).await;
-}
\ No newline at end of file
diff --git a/src/modules/test.rs b/src/modules/test.rs
deleted file mode 100644
index ba7d68d..0000000
--- a/src/modules/test.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use std::sync::Arc;
-
-// pub use crate::core::botinstance::BotInstance;
-pub use crate::core::botmodules::ModulesManager;
-
-// [ ] Load submodules
-
-mod thisguy;
-
-// [ ] init() function that accepts bot instance - this is passed to init() on submodules
-
-pub async fn init(mgr: Arc<ModulesManager>) {
-    // Modules initializer loads modules into the bot
-    // this is achieved by calling submodules that also have fn init() defined
-
-    thisguy::init(Arc::clone(&mgr)).await;
-}

From fda7afb1918c8b59c542577d480d1149884b8e81 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Thu, 28 Mar 2024 19:33:06 -0300
Subject: [PATCH 73/98] custom module working

---
 src/custom/thisguy.rs | 63 +++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 32 deletions(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index b5e895f..cf31b34 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -1,25 +1,25 @@
-use crate::core::botmodules::{ BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
-use crate::core::identity::UserRole::*;
 use crate::core::bot_actions::*;
 use crate::core::botlog;
-use std::sync::Arc;
+use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
+use crate::core::identity::UserRole::*;
 use rand::Rng;
+use std::sync::Arc;
 use tokio::time::{sleep, Duration};
+
 //use rand::Rng;
 
-async fn tsg(params: ExecBodyParams){
-
-    if params.msg.sender.name.to_lowercase() == "haruyuumei".to_lowercase()
-    || params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
+async fn tsg(params: ExecBodyParams) {
+    if params.msg.message_text == String::from("anime")
+        || params.msg.message_text == String::from("Anime")
     {
-        let phrases: [String;5] = [
-        "Aware Weebs...".to_string(),
-        "AYAYA I love anime Girls!!".to_string(),
-        "I love 2d Girls ILOST".to_string(),
-        "UOOHHHHH!!! Anime Girlssss".to_string(),
-        "Anime girls u say? peepoShy".to_string(),
+        let phrases: [String; 5] = [
+            "Aware oh no! Weebs...".to_string(),
+            "AYAYA I love anime Girls!!".to_string(),
+            "I love 2d Girls ILOST ".to_string(),
+            "UOOHHHHH!!! Anime Girlssss".to_string(),
+            "Anime girls u say? peepoShy ".to_string(),
         ];
-        
+
         let r = rand::thread_rng().gen_range(0..=4);
         let a = phrases[r].clone();
 
@@ -33,40 +33,39 @@ async fn tsg(params: ExecBodyParams){
 
         // uses chat.say_in_reply_to() for the bot controls for messages
         botlock
-        .botmgrs
-        .chat
-        .say_in_reply_to(
-            &params.msg,
-        a,
-            params.clone()
-        ).await;
+            .botmgrs
+            .chat
+            .say_in_reply_to(&params.msg, a, params.clone())
+            .await;
         sleep(Duration::from_secs_f64(0.5)).await;
+    }else {
+        
     }
-    
 }
 
-pub async fn init(mgr:&Arc<ModulesManager>){
-
-    BotCommand{
-        module:BotModule(String::from("thisguy")),
+pub async fn init(mgr: &Arc<ModulesManager>) {
+    BotCommand {
+        module: BotModule(String::from("thisguy")),
         command: String::from("anime"),
         alias: vec![String::from("Anime")],
         exec_body: actions_util::asyncbox(tesst),
         help: String::from("test"),
-        required_roles: vec![
-        BotAdmin,
-        ],
-    }.add_to_modmgr(Arc::clone(&mgr)).await;
+        required_roles: vec![BotAdmin],
+    }
+    .add_to_modmgr(Arc::clone(&mgr))
+    .await;
 
     Listener {
         module: BotModule(String::from("thisguy")),
         name: String::from("This Guy Listener"),
         exec_body: actions_util::asyncbox(tsg),
         help: String::from(""),
-    }.add_to_modmgr(Arc::clone(&mgr)).await;
+    }
+    .add_to_modmgr(Arc::clone(&mgr))
+    .await;
 }
 
-async fn tesst(params : ExecBodyParams) {
+async fn tesst(params: ExecBodyParams) {
     println!("tesst triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
         "tesst triggered!",

From f2893791b9de1813b1e5d2e9ee7ea075f93d5c67 Mon Sep 17 00:00:00 2001
From: mzntori <mzntori@proton.me>
Date: Sat, 30 Mar 2024 01:42:06 +0100
Subject: [PATCH 74/98] add reply parent functionality

---
 src/core/bot_actions.rs | 58 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index 8941654..cf7557f 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -57,9 +57,67 @@ impl ExecBodyParams {
         requestor_badge_mut
     }
 
+    /// Returns some information about the message that was replied to by the `PrivmsgMessage` contained
+    /// in the `msg` field of this struct.
+    ///
+    /// If that message replied to message return that information in form of `Some<ReplyParent>`.
+    /// Otherwise, return `None`.
+    pub fn get_parent_reply(&self) -> Option<ReplyParent> {
+        let map = &self.msg.source.tags.0;
+        let tags = [
+            "reply-parent-user-id",
+            "reply-parent-user-login",
+            "reply-parent-display-name",
+            "reply-parent-msg-id",
+            "reply-parent-msg-body"
+        ];
 
+        // filter out all tags that do not have content.
+        let tag_contents: Vec<String> = tags.iter().filter_map(|tag| {
+            if let Some(&Some(ref t)) = map.get(*tag) {
+                Some(t.clone())
+            } else {
+                None
+            }
+        }).collect();
+
+        // if no tags got filtered out return the struct.
+        // else return `None`.
+        return if tag_contents.len() == 5 {
+            Some(ReplyParent {
+                sender: TwitchUserBasics {
+                    id: tag_contents[0].clone(),
+                    login: tag_contents[1].clone(),
+                    name: tag_contents[2].clone(),
+                },
+                message_id: tag_contents[3].clone(),
+                message_text: tag_contents[4].clone(),
+                channel_login: self.msg.channel_login.clone(),
+                channel_id: self.msg.channel_id.clone(),
+            })
+        } else {
+            None
+        }
+    }
 }
 
+/// Represents the message a `PrivmsgMessage` replies to.
+/// Similar to a less detailed `PrivmsgMessage`.
+///
+/// This should not be constructed manually but only from calling `get_parent_reply()` on
+/// `ExecBodyParams`.
+///
+/// Fields that will be the same as the `PrivmsgMessage` this was generated from:
+/// - `channel_login`
+/// - `channel_id`
+#[derive(Debug, Clone, PartialEq)]
+pub struct ReplyParent {
+    pub sender: TwitchUserBasics,
+    pub message_id: String,
+    pub message_text: String,
+    pub channel_login: String,
+    pub channel_id: String,
+}
 
 
 pub mod actions_util {

From a048003e93e7f1175ea38341439e4cec7ae7f8b3 Mon Sep 17 00:00:00 2001
From: mzntori <mzntori@proton.me>
Date: Sat, 30 Mar 2024 01:47:32 +0100
Subject: [PATCH 75/98] oops forgot to add the use statement

---
 src/core/bot_actions.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index cf7557f..f5c8a66 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -1,5 +1,4 @@
-
-use twitch_irc::message::PrivmsgMessage;
+use twitch_irc::message::{PrivmsgMessage, TwitchUserBasics};
 use std::sync::Arc;
 use tokio::sync::RwLock;
 

From 72d4cf6d70924d9d2908f9aa69332a7f3b48d6e8 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Sun, 31 Mar 2024 14:37:50 -0300
Subject: [PATCH 76/98] Small changes on thisguy.rs

---
 src/custom/thisguy.rs | 86 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 69 insertions(+), 17 deletions(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index cf31b34..2a8e445 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -6,25 +6,42 @@ use rand::Rng;
 use std::sync::Arc;
 use tokio::time::{sleep, Duration};
 
-//use rand::Rng;
 
+//using the env file to get bot prefix
+use std::env;
+use dotenv::dotenv;
+
+//bot function
 async fn tsg(params: ExecBodyParams) {
-    if params.msg.message_text == String::from("anime")
-        || params.msg.message_text == String::from("Anime")
+
+    //Defining a var prefix to the prefix on the env file
+    dotenv().ok();
+    let prefix = env::var("prefix").unwrap();
+    /*  
+        defining a text with the prefix + the command name (idk how to get the command)
+        so for now i'm typing the command
+    */
+    let text = String::from(&prefix) + "This";
+    let text2 = String::from(&prefix) + "this";
+
+    //comparing the text sent with the text (prefix + command name)
+    if params.msg.message_text == text
+        || params.msg.message_text == text2
     {
-        let phrases: [String; 5] = [
-            "Aware oh no! Weebs...".to_string(),
-            "AYAYA I love anime Girls!!".to_string(),
-            "I love 2d Girls ILOST ".to_string(),
-            "UOOHHHHH!!! Anime Girlssss".to_string(),
-            "Anime girls u say? peepoShy ".to_string(),
+        let phrases: [String; 6] = [
+            "Clueless".to_string(),
+            "ICANT This guy....".to_string(),
+            "He is right tho".to_string(),
+            "KEKW true!".to_string(),
+            "OMEGALUL wth man...".to_string(),
+            "PepeLaugh El no sabe".to_string(),
         ];
 
         let r = rand::thread_rng().gen_range(0..=4);
         let a = phrases[r].clone();
 
         botlog::debug(
-            "Oh god I love anime Girls!!",
+            "This guy works!",
             Some("modules > thisguy()".to_string()),
             Some(&params.msg),
         );
@@ -39,16 +56,16 @@ async fn tsg(params: ExecBodyParams) {
             .await;
         sleep(Duration::from_secs_f64(0.5)).await;
     }else {
-        
+        println!("didn't type the proper command");
     }
 }
 
 pub async fn init(mgr: &Arc<ModulesManager>) {
     BotCommand {
         module: BotModule(String::from("thisguy")),
-        command: String::from("anime"),
-        alias: vec![String::from("Anime")],
-        exec_body: actions_util::asyncbox(tesst),
+        command: String::from("thisguy"),
+        alias: vec![String::from("Thisguy")],
+        exec_body: actions_util::asyncbox(test),
         help: String::from("test"),
         required_roles: vec![BotAdmin],
     }
@@ -65,11 +82,46 @@ pub async fn init(mgr: &Arc<ModulesManager>) {
     .await;
 }
 
-async fn tesst(params: ExecBodyParams) {
-    println!("tesst triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
+
+async fn test(params: ExecBodyParams) {
+    println!("Test triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
     botlog::debug(
-        "tesst triggered!",
+        "test triggered!",
         Some("modules > tesst()".to_string()),
         Some(&params.msg),
     );
 }
+
+
+// just testing this area, not working atm
+async fn replyer(params: ExecBodyParams)
+{
+    /*
+        check if the command message was a reply
+        get reply message parent
+        reply to the parent
+     */
+
+    //let reply_parent_message;
+    let reply_message: &String = &params.msg.message_text;
+    let my_reply:String = String::from("test");
+
+    //println!("{:?}",reply_parent_message);
+    println!("{}",reply_message);
+
+    botlog::debug(
+        "Oh god I love anime Girls!!",
+        Some("modules > thisguy()".to_string()),
+        Some(&params.msg),
+    );
+    let bot = Arc::clone(&params.bot);
+    let botlock = bot.read().await;  
+
+    // uses chat.say_in_reply_to() for the bot controls for messages
+    botlock
+        .botmgrs
+        .chat
+        .say_in_reply_to(&params.msg, my_reply, params.clone())
+        .await;
+    sleep(Duration::from_secs_f64(0.5)).await;
+}
\ No newline at end of file

From d972eb77266dedf9cdfae2189dd586699e4ca080 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Tue, 2 Apr 2024 20:11:01 -0300
Subject: [PATCH 77/98] Thisguy working partially

not fully implemented reply to the reply
---
 src/custom/thisguy.rs | 38 ++------------------------------------
 1 file changed, 2 insertions(+), 36 deletions(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index 2a8e445..b539b3e 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -6,12 +6,12 @@ use rand::Rng;
 use std::sync::Arc;
 use tokio::time::{sleep, Duration};
 
-
 //using the env file to get bot prefix
 use std::env;
 use dotenv::dotenv;
 
 //bot function
+
 async fn tsg(params: ExecBodyParams) {
 
     //Defining a var prefix to the prefix on the env file
@@ -56,7 +56,7 @@ async fn tsg(params: ExecBodyParams) {
             .await;
         sleep(Duration::from_secs_f64(0.5)).await;
     }else {
-        println!("didn't type the proper command");
+        //println!("didn't type the proper command");
     }
 }
 
@@ -91,37 +91,3 @@ async fn test(params: ExecBodyParams) {
         Some(&params.msg),
     );
 }
-
-
-// just testing this area, not working atm
-async fn replyer(params: ExecBodyParams)
-{
-    /*
-        check if the command message was a reply
-        get reply message parent
-        reply to the parent
-     */
-
-    //let reply_parent_message;
-    let reply_message: &String = &params.msg.message_text;
-    let my_reply:String = String::from("test");
-
-    //println!("{:?}",reply_parent_message);
-    println!("{}",reply_message);
-
-    botlog::debug(
-        "Oh god I love anime Girls!!",
-        Some("modules > thisguy()".to_string()),
-        Some(&params.msg),
-    );
-    let bot = Arc::clone(&params.bot);
-    let botlock = bot.read().await;  
-
-    // uses chat.say_in_reply_to() for the bot controls for messages
-    botlock
-        .botmgrs
-        .chat
-        .say_in_reply_to(&params.msg, my_reply, params.clone())
-        .await;
-    sleep(Duration::from_secs_f64(0.5)).await;
-}
\ No newline at end of file

From 7e04699b67c4191b7b4ca8107057f3b6c6b109ce Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Wed, 3 Apr 2024 10:25:24 -0300
Subject: [PATCH 78/98] making changes

---
 src/custom/thisguy.rs | 104 ++++++++++++++----------------------------
 1 file changed, 35 insertions(+), 69 deletions(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index b539b3e..0ca6de8 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -1,63 +1,44 @@
 use crate::core::bot_actions::*;
+use crate::core::botinstance::Channel;
 use crate::core::botlog;
-use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
+use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 use crate::core::identity::UserRole::*;
 use rand::Rng;
 use std::sync::Arc;
 use tokio::time::{sleep, Duration};
-
-//using the env file to get bot prefix
-use std::env;
-use dotenv::dotenv;
-
-//bot function
+const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
 async fn tsg(params: ExecBodyParams) {
 
-    //Defining a var prefix to the prefix on the env file
-    dotenv().ok();
-    let prefix = env::var("prefix").unwrap();
-    /*  
-        defining a text with the prefix + the command name (idk how to get the command)
-        so for now i'm typing the command
-    */
-    let text = String::from(&prefix) + "This";
-    let text2 = String::from(&prefix) + "this";
+    let phrases: [String; 6] = [
+        "Clueless ".to_string(),
+        "ICANT This guy....".to_string(),
+        "He is right tho".to_string(),
+        "KEKW true!".to_string(),
+        "OMEGALUL wth man...".to_string(),
+        "PepeLaugh El no sabe".to_string(),
+    ];
 
-    //comparing the text sent with the text (prefix + command name)
-    if params.msg.message_text == text
-        || params.msg.message_text == text2
-    {
-        let phrases: [String; 6] = [
-            "Clueless".to_string(),
-            "ICANT This guy....".to_string(),
-            "He is right tho".to_string(),
-            "KEKW true!".to_string(),
-            "OMEGALUL wth man...".to_string(),
-            "PepeLaugh El no sabe".to_string(),
-        ];
+    let r = rand::thread_rng().gen_range(0..=4);
+    let a = phrases[r].clone();
 
-        let r = rand::thread_rng().gen_range(0..=4);
-        let a = phrases[r].clone();
+    let test = params.get_parent_module();
 
-        botlog::debug(
-            "This guy works!",
-            Some("modules > thisguy()".to_string()),
-            Some(&params.msg),
-        );
-        let bot = Arc::clone(&params.bot);
-        let botlock = bot.read().await;
+    botlog::debug(
+        "This guy works!",
+        Some("modules > thisguy()".to_string()),
+        Some(&params.msg),
+    );
+    let bot = Arc::clone(&params.bot);
+    let botlock = bot.read().await;
 
-        // uses chat.say_in_reply_to() for the bot controls for messages
-        botlock
-            .botmgrs
-            .chat
-            .say_in_reply_to(&params.msg, a, params.clone())
-            .await;
-        sleep(Duration::from_secs_f64(0.5)).await;
-    }else {
-        //println!("didn't type the proper command");
-    }
+    // uses chat.say_in_reply_to() for the bot controls for messages
+    botlock
+        .botmgrs
+        .chat
+        .say_in_reply_to(&params.msg, a, params.clone())
+        .await;
+    sleep(Duration::from_secs_f64(0.5)).await;
 }
 
 pub async fn init(mgr: &Arc<ModulesManager>) {
@@ -65,29 +46,14 @@ pub async fn init(mgr: &Arc<ModulesManager>) {
         module: BotModule(String::from("thisguy")),
         command: String::from("thisguy"),
         alias: vec![String::from("Thisguy")],
-        exec_body: actions_util::asyncbox(test),
-        help: String::from("test"),
-        required_roles: vec![BotAdmin],
-    }
-    .add_to_modmgr(Arc::clone(&mgr))
-    .await;
-
-    Listener {
-        module: BotModule(String::from("thisguy")),
-        name: String::from("This Guy Listener"),
         exec_body: actions_util::asyncbox(tsg),
-        help: String::from(""),
+        help: String::from("test"),
+        required_roles: vec![
+            BotAdmin,
+            Mod(OF_CMD_CHANNEL),
+            Broadcaster
+            ],
     }
     .add_to_modmgr(Arc::clone(&mgr))
     .await;
-}
-
-
-async fn test(params: ExecBodyParams) {
-    println!("Test triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call
-    botlog::debug(
-        "test triggered!",
-        Some("modules > tesst()".to_string()),
-        Some(&params.msg),
-    );
-}
+}
\ No newline at end of file

From b43d6f8159cf9e107f44f8f648e2673dcc593dba Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Wed, 3 Apr 2024 10:26:14 -0300
Subject: [PATCH 79/98] Rewriten the code

working with command instead listener
---
 src/custom/thisguy.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index 0ca6de8..052f601 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -22,8 +22,6 @@ async fn tsg(params: ExecBodyParams) {
     let r = rand::thread_rng().gen_range(0..=4);
     let a = phrases[r].clone();
 
-    let test = params.get_parent_module();
-
     botlog::debug(
         "This guy works!",
         Some("modules > thisguy()".to_string()),

From 345cf97922b3cf7729f1501bd04dabc9b4869d4a Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 3 Apr 2024 13:47:59 -0400
Subject: [PATCH 80/98] enh chat.say_in_reply

---
 src/core/chat.rs | 47 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 34 insertions(+), 13 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index bb938cc..a3db701 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
 use tokio::sync::Mutex;
 
 use twitch_irc::login::StaticLoginCredentials;
-use twitch_irc::message::PrivmsgMessage;
+use twitch_irc::message::{PrivmsgMessage, ReplyToMessage};
 use twitch_irc::transport::tcp::{TCPTransport, TLS};
 use twitch_irc::TwitchIRCClient;
 
@@ -34,9 +34,14 @@ pub struct Chat {
 }
 
 
-#[derive(Clone,Debug)]
-pub enum BotMsgType<'a> {
-    SayInReplyTo(&'a PrivmsgMessage,String),
+// #[derive(Clone,Debug)] // <-- [ ] 04.03 - was having issues using this
+#[derive(Clone)] 
+// pub enum BotMsgType<'a> {
+pub enum BotMsgType {
+    // SayInReplyTo(&'a PrivmsgMessage,String),
+    // SayInReplyTo(Arc<Box<dyn ReplyToMessage>>,String),
+    // SayInReplyTo(&'a dyn ReplyToMessage,String), // [ ] 04.03 - Having issues defining it this way?
+    SayInReplyTo((String,String),String), // ( Destination Channel , Message ID to reply to ) , OutMessage // https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say_in_reply_to
     Say(String,String),
     Notif(String), // For Bot Sent Notifications
 }
@@ -59,7 +64,8 @@ impl Chat {
     }
 
     #[async_recursion]
-    pub async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
+    // pub async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
+    pub async fn send_botmsg(&self, msginput: BotMsgType, params : ExecBodyParams) {
 
         
             
@@ -72,17 +78,21 @@ impl Chat {
 
          */
 
-        
-         botlog::trace(
+        /* // [ ] 04.03 - Was having issues withh this
+        botlog::trace(
             format!("send_bot_msg params : {:?}",msginput).as_str(),
             Some("chat.rs > send_botmsg ".to_string()),
             Some(&params.msg),
         );
         Log::flush();
+        */
 
         let (channel_login,mut outmsg) = match msginput.clone() {
             BotMsgType::SayInReplyTo(msg, outmsg) => {
-                (msg.channel_login.clone(),outmsg)
+                // (msg.channel_login.clone(),outmsg)
+                // (msg.clone().channel_login().to_string(),outmsg)
+                (msg.0, // Desintation Channel
+                    outmsg)
             },
             BotMsgType::Say(a,b ) => {
                 (a.clone(),b.clone())
@@ -340,7 +350,12 @@ impl Chat {
 
                 match msginput.clone() {
                     BotMsgType::SayInReplyTo(msg, _) => {
-                        self.client.say_in_reply_to(msg, outmsg).await.unwrap();
+
+                        dbg!(msg.clone().channel_login(),msg.message_id(),outmsg.clone());
+                        self.client.say_in_reply_to(&(
+                            msg.clone().channel_login().to_string(),
+                            msg.message_id().to_string()), 
+                            outmsg).await.unwrap();
                     },
                     BotMsgType::Say(a, _) => {
                         self.client.say(a, outmsg).await.unwrap();
@@ -357,11 +372,12 @@ impl Chat {
                     channel_login.clone(), "rate limit counter increase", contextratelimiter
                 );
 
-                if let BotMsgType::SayInReplyTo(msg,_ ) = msginput {
+                if let BotMsgType::SayInReplyTo(_,_ ) = msginput {
                     botlog::trace(
                         logstr.as_str(),
                         Some("Chat > send_botmsg".to_string()),
-                        Some(msg),
+                        // Some(msg),
+                        None,
                     );
                 } else {
                     botlog::trace(
@@ -390,7 +406,9 @@ impl Chat {
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
     // #[async_recursion]
-    pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
+    // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
+    // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
+        pub async fn say_in_reply_to(&self, msg: &impl ReplyToMessage, outmsg: String , params : ExecBodyParams) {
 
         // let params_clone = params.clone();
 
@@ -443,7 +461,10 @@ impl Chat {
         // Log::flush();
 
 
-        self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await;
+        self.send_botmsg(BotMsgType::SayInReplyTo(
+                (msg.channel_login().to_string(),
+                msg.message_id().to_string()), 
+            outmsg) , params).await;
 
     }
 

From 71997037667362d3bcde0810f0138e607893d1ae Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Wed, 3 Apr 2024 15:26:04 -0300
Subject: [PATCH 81/98] reply-to-parent working

---
 src/custom/experimental/experiment001.rs | 57 ++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index dd3cba4..65bae8b 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -95,8 +95,65 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     botc1.add_to_modmgr(Arc::clone(&mgr)).await;
 
+    let bc1 = BotCommand {
+        module: BotModule(String::from("experiments001")),
+        command: String::from("rp1"), // command call name
+        alias: vec![
+            String::from("rp2"), 
+            String::from("rp3")], // String of alternative names
+        exec_body: actions_util::asyncbox(rp),
+        help: String::from("Test Command tester"),
+        required_roles: vec![
+            BotAdmin,
+            Mod(OF_CMD_CHANNEL),
+        ], 
+    };
+    bc1.add_core_to_modmgr(Arc::clone(&mgr)).await;
 }
 
+async fn rp(params : ExecBodyParams)
+{
+    //triggers if the message is a reply
+    if params.get_parent_reply().is_some(){
+
+        //getting the channel id where the message was sent
+        let channel_id = params.get_parent_reply().unwrap().channel_login;
+
+        //getting the first message id that was sent
+        let message_id = params.get_parent_reply().unwrap().message_id;
+
+        //just for testing purposes
+        //print!("{} , {}",channel_id, message_id); 
+
+        //creating a tuple with the channel id and message id
+        let answear =  
+        (
+            channel_id.clone(),
+            message_id.clone()
+        );
+
+        let bot = Arc::clone(&params.bot);
+        let botlock = bot.read().await;
+        // uses chat.say_in_reply_to() for the bot controls for messages
+        botlock
+        .botmgrs
+        .chat
+        .say_in_reply_to(
+            //using the tuple as param to the message being replied
+            &answear,
+            String::from("hey there"),
+            params.clone()
+        ).await; 
+    }   
+
+    else    
+    {
+        println!("no reply")
+    }
+}
+
+
+
 async fn good_girl(params : ExecBodyParams) {
 
     // [ ] Uses gen_ratio() to output bool based on a ratio probability .

From 6867cc7af8aee0d82baa24f1302a29005f92546a Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 3 Apr 2024 18:33:15 -0400
Subject: [PATCH 82/98] adj sayinreply to use channel & msgid

---
 src/core/chat.rs                         | 52 +++++++++++++++++-------
 src/custom/experimental/experiment001.rs | 16 +++++---
 src/custom/experimental/experiment002.rs |  4 +-
 3 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index a3db701..003c617 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -41,7 +41,8 @@ pub enum BotMsgType {
     // SayInReplyTo(&'a PrivmsgMessage,String),
     // SayInReplyTo(Arc<Box<dyn ReplyToMessage>>,String),
     // SayInReplyTo(&'a dyn ReplyToMessage,String), // [ ] 04.03 - Having issues defining it this way?
-    SayInReplyTo((String,String),String), // ( Destination Channel , Message ID to reply to ) , OutMessage // https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say_in_reply_to
+    // SayInReplyTo((String,String),String), // ( Destination Channel , Message ID to reply to ) , OutMessage // https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say_in_reply_to
+    SayInReplyTo(Channel,String,String), // ( Destination Channel , Message ID to reply to , OutMessage ) // https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say_in_reply_to
     Say(String,String),
     Notif(String), // For Bot Sent Notifications
 }
@@ -88,10 +89,11 @@ impl Chat {
         */
 
         let (channel_login,mut outmsg) = match msginput.clone() {
-            BotMsgType::SayInReplyTo(msg, outmsg) => {
+            // BotMsgType::SayInReplyTo(msg, outmsg) => {
+            BotMsgType::SayInReplyTo(chnl, _, outmsg) => {
                 // (msg.channel_login.clone(),outmsg)
                 // (msg.clone().channel_login().to_string(),outmsg)
-                (msg.0, // Desintation Channel
+                (chnl.0.to_lowercase(), // Desintation Channel
                     outmsg)
             },
             BotMsgType::Say(a,b ) => {
@@ -123,13 +125,16 @@ impl Chat {
             ).await;
 
         if !params.bot.read().await.bot_channels.contains(&Channel(channel_login.clone())) {
+
+            dbg!("ISSUE : NONJOINED CHANNEL",&params.bot.read().await.bot_channels,Channel(channel_login.clone()));
             botlog::warn(
                 &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()),
                 Some("Chat > send_botmsg".to_string()),
                 None,
             );
 
-            if let BotMsgType::SayInReplyTo(_prvmsg,_outmsg) = msginput {
+            // if let BotMsgType::SayInReplyTo(_prvmsg,_outmsg) = msginput {
+            if let BotMsgType::SayInReplyTo(_chnl,_msgid, _outmsg) = msginput {
 
                 self.send_botmsg(BotMsgType::Notif(
                     "uuh Bot can't send to a channel it isn't joined".to_string(), 
@@ -177,7 +182,8 @@ impl Chat {
 
             match msginput {
                 BotMsgType::Notif(_) => (), // Do nothing with Notif > We'll validate the user later to handle
-                BotMsgType::SayInReplyTo(_, _) | BotMsgType::Say(_,_) => {
+                // BotMsgType::SayInReplyTo(_, _) | BotMsgType::Say(_,_) => {
+                BotMsgType::SayInReplyTo(_, _, _) | BotMsgType::Say(_,_) => {
                             
                         botlog::trace(
                             "BEFORE potential Async recursion",
@@ -276,7 +282,8 @@ impl Chat {
                             return;
                         }
                     },
-                    BotMsgType::SayInReplyTo(_,_ ) | BotMsgType::Say(_,_) => {
+                    // BotMsgType::SayInReplyTo(_,_ ) | BotMsgType::Say(_,_) => {
+                    BotMsgType::SayInReplyTo(_,_,_ ) | BotMsgType::Say(_,_) => {
                         // If the BotMsg a Say/SayInReplyTo (from Developer or Chatter) , and the Sender does not have Specific Roles in the Source Channel Sent
 
                         self.send_botmsg(BotMsgType::Notif(
@@ -349,18 +356,25 @@ impl Chat {
                 }
 
                 match msginput.clone() {
-                    BotMsgType::SayInReplyTo(msg, _) => {
+                    // BotMsgType::SayInReplyTo(msg, _) => {
+                    // BotMsgType::SayInReplyTo(msg, _, _) => {
+                    BotMsgType::SayInReplyTo(chnl,msgid, _) => {
+
+                        // dbg!(msg.clone().channel_login(),msg.message_id(),outmsg.clone());
+                        dbg!(chnl.clone(),msgid.clone(),outmsg.clone());
 
-                        dbg!(msg.clone().channel_login(),msg.message_id(),outmsg.clone());
                         self.client.say_in_reply_to(&(
-                            msg.clone().channel_login().to_string(),
-                            msg.message_id().to_string()), 
+                            chnl.0,
+                            msgid), 
                             outmsg).await.unwrap();
                     },
                     BotMsgType::Say(a, _) => {
                         self.client.say(a, outmsg).await.unwrap();
                     }
                     BotMsgType::Notif(outmsg) => {
+
+                        // dbg!(chnl.clone(),msgid.clone(),outmsg.clone());
+                        dbg!(params.msg.channel_login(),params.msg.message_id());
                         self.client.say_in_reply_to(&params.msg, outmsg).await.unwrap();
                     }
                 }
@@ -372,7 +386,8 @@ impl Chat {
                     channel_login.clone(), "rate limit counter increase", contextratelimiter
                 );
 
-                if let BotMsgType::SayInReplyTo(_,_ ) = msginput {
+                // if let BotMsgType::SayInReplyTo(_,_ ) = msginput {
+                if let BotMsgType::SayInReplyTo(_,_,_ ) = msginput {
                     botlog::trace(
                         logstr.as_str(),
                         Some("Chat > send_botmsg".to_string()),
@@ -408,7 +423,14 @@ impl Chat {
     // #[async_recursion]
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
-        pub async fn say_in_reply_to(&self, msg: &impl ReplyToMessage, outmsg: String , params : ExecBodyParams) {
+    // pub async fn say_in_reply_to(&self, msg: &impl ReplyToMessage, outmsg: String , params : ExecBodyParams) {
+    pub async fn say_in_reply_to(
+        &self, 
+        destination_channel : Channel , 
+        reply_message_id : String ,
+        outmsg: String , 
+        params : ExecBodyParams) 
+    {
 
         // let params_clone = params.clone();
 
@@ -462,9 +484,9 @@ impl Chat {
 
 
         self.send_botmsg(BotMsgType::SayInReplyTo(
-                (msg.channel_login().to_string(),
-                msg.message_id().to_string()), 
-            outmsg) , params).await;
+                destination_channel,
+                reply_message_id, 
+                outmsg) , params).await;
 
     }
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 65bae8b..e774055 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -15,6 +15,7 @@ const OF_CMD_CHANNEL:Channel = Channel(String::new());
 
 
 use rand::Rng;
+use twitch_irc::message::ReplyToMessage;
 use std::sync::Arc;
 
 use crate::core::bot_actions::ExecBodyParams;
@@ -140,7 +141,8 @@ async fn rp(params : ExecBodyParams)
         .chat
         .say_in_reply_to(
             //using the tuple as param to the message being replied
-            &answear,
+            Channel(answear.0),
+            answear.1,
             String::from("hey there"),
             params.clone()
         ).await; 
@@ -188,7 +190,8 @@ async fn good_girl(params : ExecBodyParams) {
             .botmgrs
             .chat
             .say_in_reply_to(
-                &params.msg, 
+                Channel(params.clone().msg.channel_login().to_string()),
+                params.clone().msg.message_id().to_string(), 
                 String::from("GoodGirl xdd "),
                 params.clone()
             ).await;
@@ -228,7 +231,8 @@ async fn babygirl(params : ExecBodyParams) {
         .botmgrs
         .chat
         .say_in_reply_to(
-            &params.msg, 
+            Channel(params.clone().msg.channel_login().to_string()),
+            params.clone().msg.message_id().to_string(), 
             String::from("16:13 notohh: cafdk"),
             params.clone()
         ).await;
@@ -240,7 +244,8 @@ async fn babygirl(params : ExecBodyParams) {
     .botmgrs
     .chat
     .say_in_reply_to(
-        &params.msg, 
+        Channel(params.clone().msg.channel_login().to_string()),
+        params.clone().msg.message_id().to_string(), 
         String::from("16:13 notohh: have fun eating princess"),
         params.clone()
     ).await;
@@ -252,7 +257,8 @@ async fn babygirl(params : ExecBodyParams) {
     .botmgrs
     .chat
     .say_in_reply_to(
-        &params.msg, 
+        Channel(params.clone().msg.channel_login().to_string()),
+        params.clone().msg.message_id().to_string(), 
         String::from("16:13 notohh: baby girl"),
         params.clone()
     ).await;
diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs
index a4ecb25..a7d1610 100644
--- a/src/custom/experimental/experiment002.rs
+++ b/src/custom/experimental/experiment002.rs
@@ -17,6 +17,7 @@ const OF_CMD_CHANNEL:Channel = Channel(String::new());
 use std::sync::Arc;
 
 use chrono::{TimeZone,Local};
+use twitch_irc::message::ReplyToMessage;
 
 
 use crate::core::bot_actions::ExecBodyParams;
@@ -180,7 +181,8 @@ async fn sayout(params : ExecBodyParams) {
             .botmgrs
             .chat
             .say_in_reply_to(
-                &params.msg, 
+                Channel(params.clone().msg.channel_login().to_string()),
+                params.clone().msg.message_id().to_string(), 
                 String::from("Invalid arguments"),
                 params.clone()
             ).await;

From 62b6399e69eb8cc6aba21d759d50f85ed4974ca3 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 3 Apr 2024 19:04:21 -0400
Subject: [PATCH 83/98] chat.say_in_reply

---
 src/core/chat.rs                         | 22 ++++++++++++++++++++++
 src/custom/experimental/experiment001.rs | 20 ++++++++++++++------
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/src/core/chat.rs b/src/core/chat.rs
index 003c617..82bc3f6 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -418,6 +418,21 @@ impl Chat {
     }
 
 
+    pub async fn say_in_reply(
+        &self, 
+        destination_channel : Channel , 
+        outmsg: String , 
+        params : ExecBodyParams) 
+    {
+
+        self.send_botmsg(BotMsgType::SayInReplyTo(
+            destination_channel,
+            params.msg.message_id().to_string(), 
+            outmsg) , params).await;
+
+
+    }
+
 
     // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
     // #[async_recursion]
@@ -490,6 +505,9 @@ impl Chat {
 
     }
 
+
+
+
     // pub async fn say(&self, channel_login: String, message: String) {
     pub async fn say(&self, channel_login: String, message: String , params : ExecBodyParams) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
@@ -497,6 +515,10 @@ impl Chat {
         self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message), params).await;
     }
 
+
+
+
+
     async fn _me(&self, _: String, _: String) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index e774055..cb75ad2 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -230,9 +230,8 @@ async fn babygirl(params : ExecBodyParams) {
     botlock
         .botmgrs
         .chat
-        .say_in_reply_to(
+        .say_in_reply(
             Channel(params.clone().msg.channel_login().to_string()),
-            params.clone().msg.message_id().to_string(), 
             String::from("16:13 notohh: cafdk"),
             params.clone()
         ).await;
@@ -243,9 +242,8 @@ async fn babygirl(params : ExecBodyParams) {
     botlock
     .botmgrs
     .chat
-    .say_in_reply_to(
+    .say_in_reply(
         Channel(params.clone().msg.channel_login().to_string()),
-        params.clone().msg.message_id().to_string(), 
         String::from("16:13 notohh: have fun eating princess"),
         params.clone()
     ).await;
@@ -253,12 +251,22 @@ async fn babygirl(params : ExecBodyParams) {
 
     sleep(Duration::from_secs_f64(2.0)).await;
 
+    // botlock
+    // .botmgrs
+    // .chat
+    // .say_in_reply_to(
+    //     Channel(params.clone().msg.channel_login().to_string()),
+    //     params.clone().msg.message_id().to_string(), 
+    //     String::from("16:13 notohh: baby girl"),
+    //     params.clone()
+    // ).await;
+
+
     botlock
     .botmgrs
     .chat
-    .say_in_reply_to(
+    .say_in_reply(
         Channel(params.clone().msg.channel_login().to_string()),
-        params.clone().msg.message_id().to_string(), 
         String::from("16:13 notohh: baby girl"),
         params.clone()
     ).await;

From 8adab21761cd3c9bc6837518006140fbcc82f4f4 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 3 Apr 2024 19:40:18 -0400
Subject: [PATCH 84/98] comments cleanup

---
 src/core/botlog.rs                       | 21 ++----
 src/core/botmodules.rs                   |  1 -
 src/core/chat.rs                         | 85 +-----------------------
 src/core/identity.rs                     |  4 --
 src/custom/experimental/experiment001.rs | 11 ---
 5 files changed, 10 insertions(+), 112 deletions(-)

diff --git a/src/core/botlog.rs b/src/core/botlog.rs
index 27272d2..48ae783 100644
--- a/src/core/botlog.rs
+++ b/src/core/botlog.rs
@@ -24,11 +24,10 @@ debug = "Checking bot actions",
 pub fn trace(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgMessage>) {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
@@ -45,11 +44,10 @@ pub fn trace(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&Privmsg
 pub fn debug(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgMessage>) {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
@@ -66,11 +64,10 @@ pub fn debug(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&Privmsg
 pub fn info(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgMessage>) {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
@@ -87,11 +84,10 @@ pub fn info(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgM
 pub fn notice(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgMessage>) {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
@@ -108,11 +104,10 @@ pub fn notice(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&Privms
 pub fn warn(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgMessage>) {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
@@ -129,11 +124,10 @@ pub fn warn(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgM
 pub fn error(in_msg: &str, in_module: Option<String>, in_prvmsg: Option<&PrivmsgMessage>) {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
@@ -154,11 +148,10 @@ pub fn fatal<'a>(
 ) -> &'a str {
     let (chnl, chatter) = match in_prvmsg {
         Some(prvmsg) => {
-            //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text));
             (
                 Some(prvmsg.channel_login.clone()),
                 Some(prvmsg.sender.name.clone()),
-            ) // <-- Clone fine atm while we're just working with Strings
+            ) 
         }
         None => (None, None),
     };
diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs
index c104fdd..408b2d5 100644
--- a/src/core/botmodules.rs
+++ b/src/core/botmodules.rs
@@ -253,7 +253,6 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     // 2. Add the BotAction to ModulesManager
     botc1.add_core_to_modmgr(Arc::clone(&mgr)).await;
     
-    // async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) {
     async fn cmd_disable(params : ExecBodyParams) {
         /*
             There should be additional validation checks
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 82bc3f6..3ed28ce 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -34,14 +34,8 @@ pub struct Chat {
 }
 
 
-// #[derive(Clone,Debug)] // <-- [ ] 04.03 - was having issues using this
-#[derive(Clone)] 
-// pub enum BotMsgType<'a> {
+#[derive(Clone,Debug)] 
 pub enum BotMsgType {
-    // SayInReplyTo(&'a PrivmsgMessage,String),
-    // SayInReplyTo(Arc<Box<dyn ReplyToMessage>>,String),
-    // SayInReplyTo(&'a dyn ReplyToMessage,String), // [ ] 04.03 - Having issues defining it this way?
-    // SayInReplyTo((String,String),String), // ( Destination Channel , Message ID to reply to ) , OutMessage // https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say_in_reply_to
     SayInReplyTo(Channel,String,String), // ( Destination Channel , Message ID to reply to , OutMessage ) // https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say_in_reply_to
     Say(String,String),
     Notif(String), // For Bot Sent Notifications
@@ -65,7 +59,6 @@ impl Chat {
     }
 
     #[async_recursion]
-    // pub async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) {
     pub async fn send_botmsg(&self, msginput: BotMsgType, params : ExecBodyParams) {
 
         
@@ -79,20 +72,16 @@ impl Chat {
 
          */
 
-        /* // [ ] 04.03 - Was having issues withh this
         botlog::trace(
             format!("send_bot_msg params : {:?}",msginput).as_str(),
             Some("chat.rs > send_botmsg ".to_string()),
             Some(&params.msg),
         );
         Log::flush();
-        */
+        
 
         let (channel_login,mut outmsg) = match msginput.clone() {
-            // BotMsgType::SayInReplyTo(msg, outmsg) => {
             BotMsgType::SayInReplyTo(chnl, _, outmsg) => {
-                // (msg.channel_login.clone(),outmsg)
-                // (msg.clone().channel_login().to_string(),outmsg)
                 (chnl.0.to_lowercase(), // Desintation Channel
                     outmsg)
             },
@@ -133,7 +122,6 @@ impl Chat {
                 None,
             );
 
-            // if let BotMsgType::SayInReplyTo(_prvmsg,_outmsg) = msginput {
             if let BotMsgType::SayInReplyTo(_chnl,_msgid, _outmsg) = msginput {
 
                 self.send_botmsg(BotMsgType::Notif(
@@ -182,7 +170,6 @@ impl Chat {
 
             match msginput {
                 BotMsgType::Notif(_) => (), // Do nothing with Notif > We'll validate the user later to handle
-                // BotMsgType::SayInReplyTo(_, _) | BotMsgType::Say(_,_) => {
                 BotMsgType::SayInReplyTo(_, _, _) | BotMsgType::Say(_,_) => {
                             
                         botlog::trace(
@@ -248,7 +235,7 @@ impl Chat {
              let botlock = botclone.read().await;
              let id = botlock.get_identity();
              let id = Arc::clone(&id);
-             let idlock = id.read().await; // <-- [x] 03.24 - seems to work
+             let idlock = id.read().await; 
              let user_roles = idlock.getspecialuserroles(
                 params.get_sender(), 
                 Some(Channel(channel_login.clone()))
@@ -282,7 +269,6 @@ impl Chat {
                             return;
                         }
                     },
-                    // BotMsgType::SayInReplyTo(_,_ ) | BotMsgType::Say(_,_) => {
                     BotMsgType::SayInReplyTo(_,_,_ ) | BotMsgType::Say(_,_) => {
                         // If the BotMsg a Say/SayInReplyTo (from Developer or Chatter) , and the Sender does not have Specific Roles in the Source Channel Sent
 
@@ -337,7 +323,6 @@ impl Chat {
         );
 
         let contextratelimiter = rllock
-            // .get_mut()
             .get_mut(&Channel(channel_login.to_lowercase().clone()))
             .expect("ERROR: Issue with Rate limiters");
 
@@ -356,11 +341,8 @@ impl Chat {
                 }
 
                 match msginput.clone() {
-                    // BotMsgType::SayInReplyTo(msg, _) => {
-                    // BotMsgType::SayInReplyTo(msg, _, _) => {
                     BotMsgType::SayInReplyTo(chnl,msgid, _) => {
 
-                        // dbg!(msg.clone().channel_login(),msg.message_id(),outmsg.clone());
                         dbg!(chnl.clone(),msgid.clone(),outmsg.clone());
 
                         self.client.say_in_reply_to(&(
@@ -373,7 +355,6 @@ impl Chat {
                     }
                     BotMsgType::Notif(outmsg) => {
 
-                        // dbg!(chnl.clone(),msgid.clone(),outmsg.clone());
                         dbg!(params.msg.channel_login(),params.msg.message_id());
                         self.client.say_in_reply_to(&params.msg, outmsg).await.unwrap();
                     }
@@ -386,12 +367,10 @@ impl Chat {
                     channel_login.clone(), "rate limit counter increase", contextratelimiter
                 );
 
-                // if let BotMsgType::SayInReplyTo(_,_ ) = msginput {
                 if let BotMsgType::SayInReplyTo(_,_,_ ) = msginput {
                     botlog::trace(
                         logstr.as_str(),
                         Some("Chat > send_botmsg".to_string()),
-                        // Some(msg),
                         None,
                     );
                 } else {
@@ -433,12 +412,6 @@ impl Chat {
 
     }
 
-
-    // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) {
-    // #[async_recursion]
-    // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
-    // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) {
-    // pub async fn say_in_reply_to(&self, msg: &impl ReplyToMessage, outmsg: String , params : ExecBodyParams) {
     pub async fn say_in_reply_to(
         &self, 
         destination_channel : Channel , 
@@ -447,57 +420,6 @@ impl Chat {
         params : ExecBodyParams) 
     {
 
-        // let params_clone = params.clone();
-
-        // let botclone = Arc::clone(&params_clone.bot);
-        // let botlock = botclone.read().await;
-        // let id = botlock.get_identity();
-        // let id = Arc::clone(&id);
-
-        // // botlog::trace(
-        // //     "ACQUIRING WRITE LOCK : ID",
-        // //     Some("Chat > send_botmsg".to_string()),
-        // //     Some(&params.msg),
-        // // );
-        // // Log::flush();
-
-        // botlog::trace(
-        //     "ACQUIRING READ LOCK : ID",
-        //     Some("Chat > send_botmsg".to_string()),
-        //     Some(&params.msg),
-        // );
-        // Log::flush();
-
-        
-        // // let idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it
-        // let idlock = id.read().await; // <-- [ ] 03.24 - seems to work
-        // let a = idlock.getspecialuserroles(params.get_sender(), Some(Channel(msg.channel_login.clone()))).await;
-        // botlog::trace(
-        //     format!("GETSPECIALUSERROLES RESULT : {:?}",a).as_str(),
-        //     Some("Chat > send_botmsg".to_string()),
-        //     Some(&params.msg),
-        // );
-        // Log::flush();
-        
-        
-
-        // // botlog::trace(
-        // //     "ACQUIRED WRITE LOCK : ID",
-        // //     Some("Chat > send_botmsg".to_string()),
-        // //     Some(&params.msg),
-        // // );
-        // // Log::flush();
-
-
-        
-        // botlog::trace(
-        //     "ACQUIRED READ LOCK : ID",
-        //     Some("Chat > send_botmsg".to_string()),
-        //     Some(&params.msg),
-        // );
-        // Log::flush();
-
-
         self.send_botmsg(BotMsgType::SayInReplyTo(
                 destination_channel,
                 reply_message_id, 
@@ -508,7 +430,6 @@ impl Chat {
 
 
 
-    // pub async fn say(&self, channel_login: String, message: String) {
     pub async fn say(&self, channel_login: String, message: String , params : ExecBodyParams) {
         // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
 
diff --git a/src/core/identity.rs b/src/core/identity.rs
index dc2da72..726bbdf 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -23,13 +23,10 @@ use std::env;
 
 fn adminvector() -> Vec<String> {
     vec![String::from("ModulatingForce")]
-    //vec![]
 }
 
 
 pub fn otherbots_vector() -> Vec<String> {
-    // vec![String::from("ModulatingForce")]
-    // //vec![]
 
     dotenv().ok();
     let mut other_bots = Vec::new();
@@ -1467,7 +1464,6 @@ impl IdentityManager {
                     return ChangeResult::NoChange("Already does not have VIP role".to_string());
                 } 
                 else {
-                    // self.affirm_chatter_in_db(trgchatter.clone()).await;
 
                     self.remove_role(trgchatter.clone(), UserRole::VIP(channel.clone())).await;
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index cb75ad2..897384d 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -251,17 +251,6 @@ async fn babygirl(params : ExecBodyParams) {
 
     sleep(Duration::from_secs_f64(2.0)).await;
 
-    // botlock
-    // .botmgrs
-    // .chat
-    // .say_in_reply_to(
-    //     Channel(params.clone().msg.channel_login().to_string()),
-    //     params.clone().msg.message_id().to_string(), 
-    //     String::from("16:13 notohh: baby girl"),
-    //     params.clone()
-    // ).await;
-
-
     botlock
     .botmgrs
     .chat

From fde96ac8956d35c884f51afb01140a3faeb92b80 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Wed, 3 Apr 2024 19:45:18 -0400
Subject: [PATCH 85/98] clippy cleanup

---
 src/core/bot_actions.rs                  | 5 +++--
 src/core/chat.rs                         | 2 +-
 src/custom/experimental/experiment001.rs | 1 -
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs
index f5c8a66..7ab34a0 100644
--- a/src/core/bot_actions.rs
+++ b/src/core/bot_actions.rs
@@ -73,7 +73,8 @@ impl ExecBodyParams {
 
         // filter out all tags that do not have content.
         let tag_contents: Vec<String> = tags.iter().filter_map(|tag| {
-            if let Some(&Some(ref t)) = map.get(*tag) {
+            // if let Some(&Some(ref t)) = map.get(*tag) {
+                if let Some(Some(t)) = map.get(*tag) {
                 Some(t.clone())
             } else {
                 None
@@ -82,7 +83,7 @@ impl ExecBodyParams {
 
         // if no tags got filtered out return the struct.
         // else return `None`.
-        return if tag_contents.len() == 5 {
+        if tag_contents.len() == 5 {
             Some(ReplyParent {
                 sender: TwitchUserBasics {
                     id: tag_contents[0].clone(),
diff --git a/src/core/chat.rs b/src/core/chat.rs
index 3ed28ce..43984bc 100644
--- a/src/core/chat.rs
+++ b/src/core/chat.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
 use tokio::sync::Mutex;
 
 use twitch_irc::login::StaticLoginCredentials;
-use twitch_irc::message::{PrivmsgMessage, ReplyToMessage};
+use twitch_irc::message::ReplyToMessage;
 use twitch_irc::transport::tcp::{TCPTransport, TLS};
 use twitch_irc::TwitchIRCClient;
 
diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs
index 897384d..18d7aaa 100644
--- a/src/custom/experimental/experiment001.rs
+++ b/src/custom/experimental/experiment001.rs
@@ -147,7 +147,6 @@ async fn rp(params : ExecBodyParams)
             params.clone()
         ).await; 
     }   
-
     else    
     {
         println!("no reply")

From 78634f3ffe8cfd373e70c8e718d0bff590398a70 Mon Sep 17 00:00:00 2001
From: WoodpeckerCI <woodpecker@flake.sh>
Date: Mon, 8 Apr 2024 13:59:49 +0000
Subject: [PATCH 86/98] flake.lock: update

---
 flake.lock | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/flake.lock b/flake.lock
index 67734d7..84f1b48 100644
--- a/flake.lock
+++ b/flake.lock
@@ -6,11 +6,11 @@
         "rust-analyzer-src": "rust-analyzer-src"
       },
       "locked": {
-        "lastModified": 1706768574,
-        "narHash": "sha256-4o6TMpzBHO659EiJTzd/EGQGUDdbgwKwhqf3u6b23U8=",
+        "lastModified": 1711952616,
+        "narHash": "sha256-WJvDdOph001fA1Ap3AyaQtz/afJAe7meSG5uJAdSE+A=",
         "owner": "nix-community",
         "repo": "fenix",
-        "rev": "668102037129923cd0fc239d864fce71eabdc6a3",
+        "rev": "209048d7c545905c470f6f8c05c5061f391031a8",
         "type": "github"
       },
       "original": {
@@ -22,11 +22,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1706550542,
-        "narHash": "sha256-UcsnCG6wx++23yeER4Hg18CXWbgNpqNXcHIo5/1Y+hc=",
+        "lastModified": 1711703276,
+        "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "97b17f32362e475016f942bbdfda4a4a72a8a652",
+        "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
         "type": "github"
       },
       "original": {
@@ -38,11 +38,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1708296515,
-        "narHash": "sha256-FyF489fYNAUy7b6dkYV6rGPyzp+4tThhr80KNAaF/yY=",
+        "lastModified": 1712439257,
+        "narHash": "sha256-aSpiNepFOMk9932HOax0XwNxbA38GOUVOiXfUVPOrck=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "b98a4e1746acceb92c509bc496ef3d0e5ad8d4aa",
+        "rev": "ff0dbd94265ac470dda06a657d5fe49de93b4599",
         "type": "github"
       },
       "original": {
@@ -61,11 +61,11 @@
     "rust-analyzer-src": {
       "flake": false,
       "locked": {
-        "lastModified": 1706735270,
-        "narHash": "sha256-IJk+UitcJsxzMQWm9pa1ZbJBriQ4ginXOlPyVq+Cu40=",
+        "lastModified": 1711885694,
+        "narHash": "sha256-dyezzeSbWMpflma+E9USmvSxuLgGcNGcGw3cOnX36ko=",
         "owner": "rust-lang",
         "repo": "rust-analyzer",
-        "rev": "42cb1a2bd79af321b0cc503d2960b73f34e2f92b",
+        "rev": "e4a405f877efd820bef9c0e77a02494e47c17512",
         "type": "github"
       },
       "original": {

From 087e76388d3c7a6052531dd8b514e6f621f55c7c Mon Sep 17 00:00:00 2001
From: notohh <github@notohh.dev>
Date: Mon, 8 Apr 2024 11:11:05 -0400
Subject: [PATCH 87/98] nix: init rewrite

first pass of my nix rewrite

nix: rename module

nix: update module

nix: update module

nix: update module

nix: refactor

nix: remove package option

nix: fix serviceConfig

nix: add package back to module

nix: update module

nix: update module

nix: update module

nix: update module

remove default.nix
---
 .gitignore     |  5 +++-
 flake.lock     | 30 +++++++++++++++-----
 flake.nix      | 77 ++++++++++++++++++++++++++++++++------------------
 nix/module.nix | 30 ++++++++++++++++++++
 4 files changed, 107 insertions(+), 35 deletions(-)
 create mode 100644 nix/module.nix

diff --git a/.gitignore b/.gitignore
index 5c5e6b4..51b0be2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,4 +22,7 @@ target/
 *.log
 
 # debug
-.vscode/
\ No newline at end of file
+.vscode/
+
+# nix
+result/
\ No newline at end of file
diff --git a/flake.lock b/flake.lock
index 84f1b48..f66c5b5 100644
--- a/flake.lock
+++ b/flake.lock
@@ -38,16 +38,16 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1712439257,
-        "narHash": "sha256-aSpiNepFOMk9932HOax0XwNxbA38GOUVOiXfUVPOrck=",
-        "owner": "nixos",
+        "lastModified": 1712543224,
+        "narHash": "sha256-9RSfZL1TKYdGxZwgDxwtBtsKMGR4Zgn+DAnF9s71/lU=",
+        "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "ff0dbd94265ac470dda06a657d5fe49de93b4599",
+        "rev": "b0dab7cc34ef4d8a1b2de36178da801090bcb271",
         "type": "github"
       },
       "original": {
-        "owner": "nixos",
-        "ref": "nixos-unstable",
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
         "repo": "nixpkgs",
         "type": "github"
       }
@@ -55,7 +55,8 @@
     "root": {
       "inputs": {
         "fenix": "fenix",
-        "nixpkgs": "nixpkgs_2"
+        "nixpkgs": "nixpkgs_2",
+        "systems": "systems"
       }
     },
     "rust-analyzer-src": {
@@ -74,6 +75,21 @@
         "repo": "rust-analyzer",
         "type": "github"
       }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1689347949,
+        "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
+        "owner": "nix-systems",
+        "repo": "default-linux",
+        "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default-linux",
+        "type": "github"
+      }
     }
   },
   "root": "root",
diff --git a/flake.nix b/flake.nix
index c6be631..f29c01a 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,39 +1,62 @@
 {
-  description = "forcebot_rs flake";
+  description = "A basic flake";
 
   inputs = {
-    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+    systems.url = "github:nix-systems/default-linux";
+    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
     fenix.url = "github:nix-community/fenix/monthly";
   };
+
   outputs = {
+    self,
+    systems,
     nixpkgs,
     fenix,
-    ...
   } @ inputs: let
-    system = "x86_64-linux";
-    overlays = [fenix.overlays.default];
-    pkgs = import nixpkgs {
-      inherit system overlays;
-    };
+    eachSystem = nixpkgs.lib.genAttrs (import systems);
+    pkgsFor = eachSystem (system:
+      import nixpkgs {
+        localSystem.system = system;
+        overlays = [fenix.overlays.default];
+      });
   in {
-    devShells.${system}.default = pkgs.mkShell {
-      name = "forcebot_rs-devenv";
-      nativeBuildInputs = [pkgs.pkg-config];
-      buildInputs = with pkgs; [openssl libiconv];
-      packages = with pkgs; [
-        nil
-        alejandra
-        rust-analyzer-nightly
-        (fenix.packages.${system}.complete.withComponents [
-          "cargo"
-          "clippy"
-          "rust-src"
-          "rustc"
-          "rustfmt"
-        ])
-      ];
-      RUST_BACKTRACE = 1;
-      RUST_SRC_PATH = "${fenix.packages.${system}.complete.rust-src}/lib/rustlib/src/rust/library";
-    };
+    packages = eachSystem (system: let
+      pkgs = nixpkgs.legacyPackages.${system};
+    in {
+      default = pkgsFor.${system}.rustPlatform.buildRustPackage {
+        pname = "forcebot_rs";
+        version = "v0.1";
+
+        src = self;
+
+        cargoLock = {
+          lockFile = ./Cargo.lock;
+        };
+
+        nativeBuildInputs = with pkgs; [pkg-config];
+        buildInputs = with pkgs; [openssl];
+
+        doCheck = false;
+      };
+    });
+    devShells = eachSystem (system: {
+      default = pkgsFor.${system}.mkShell {
+        packages = with pkgsFor.${system}; [
+          nil
+          alejandra
+          rust-analyzer-nightly
+          (fenix.packages.${system}.complete.withComponents [
+            "cargo"
+            "clippy"
+            "rust-src"
+            "rustc"
+            "rustfmt"
+          ])
+        ];
+        RUST_BACKTRACE = 1;
+        RUST_SRC_PATH = "${fenix.packages.${system}.complete.rust-src}/lib/rustlib/src/rust/library";
+      };
+    });
+    nixosModules.default = import ./nix/module.nix {inherit self;};
   };
 }
diff --git a/nix/module.nix b/nix/module.nix
new file mode 100644
index 0000000..b615be1
--- /dev/null
+++ b/nix/module.nix
@@ -0,0 +1,30 @@
+{self}: {
+  pkgs,
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) types;
+  inherit (lib.modules) mkIf;
+  inherit (lib.options) mkOption mkEnableOption;
+  inherit (pkgs.stdenv.hostPlatform) system;
+  cfg = config.services.forcebot_rs;
+in {
+  options.services.forcebot_rs = {
+    enable = mkEnableOption ''
+      Enable forcebot
+    '';
+
+    package = mkOption {
+      type = types.package;
+      default = self.packages.${system}.default;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.forcebot_rs = {
+      wantedBy = ["multi-user.target"];
+      serviceConfig.ExecStart = "${cfg.package}/bin/forcebot_rs";
+    };
+  };
+}

From 604c26647e817b05feeeb75e5f300708e4f02291 Mon Sep 17 00:00:00 2001
From: notohh <github@notohh.dev>
Date: Mon, 8 Apr 2024 17:59:36 -0400
Subject: [PATCH 88/98] nix: read version from cargo.toml

fix spelling error
---
 flake.nix | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/flake.nix b/flake.nix
index f29c01a..bfd6561 100644
--- a/flake.nix
+++ b/flake.nix
@@ -22,10 +22,11 @@
   in {
     packages = eachSystem (system: let
       pkgs = nixpkgs.legacyPackages.${system};
+      version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
     in {
       default = pkgsFor.${system}.rustPlatform.buildRustPackage {
         pname = "forcebot_rs";
-        version = "v0.1";
+        version = "${version}";
 
         src = self;
 

From 200d2a86d3f63191fbc28a335b13b928bd816f61 Mon Sep 17 00:00:00 2001
From: notohh <github@notohh.dev>
Date: Mon, 8 Apr 2024 18:45:30 -0400
Subject: [PATCH 89/98] nix: add pre-commit-hooks

---
 .gitignore     |   5 +-
 flake.lock     | 127 ++++++++++++++++++++++++++++++++++++++++++++++++-
 flake.nix      |  21 +++++++-
 nix/module.nix |   2 +-
 statix.toml    |   3 ++
 5 files changed, 153 insertions(+), 5 deletions(-)
 create mode 100644 statix.toml

diff --git a/.gitignore b/.gitignore
index 51b0be2..e602fce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,4 +25,7 @@ target/
 .vscode/
 
 # nix
-result/
\ No newline at end of file
+result/
+
+# pre-commit
+/.pre-commit-config.yaml
diff --git a/flake.lock b/flake.lock
index f66c5b5..cf7dd31 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,6 +20,61 @@
         "type": "github"
       }
     },
+    "flake-compat": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1710146030,
+        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "gitignore": {
+      "inputs": {
+        "nixpkgs": [
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
     "nixpkgs": {
       "locked": {
         "lastModified": 1711703276,
@@ -36,6 +91,22 @@
         "type": "github"
       }
     },
+    "nixpkgs-stable": {
+      "locked": {
+        "lastModified": 1710695816,
+        "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "614b4613980a522ba49f0d194531beddbb7220d3",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-23.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "nixpkgs_2": {
       "locked": {
         "lastModified": 1712543224,
@@ -52,11 +123,50 @@
         "type": "github"
       }
     },
+    "nixpkgs_3": {
+      "locked": {
+        "lastModified": 1710765496,
+        "narHash": "sha256-p7ryWEeQfMwTB6E0wIUd5V2cFTgq+DRRBz2hYGnJZyA=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "e367f7a1fb93137af22a3908f00b9a35e2d286a7",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "pre-commit-hooks": {
+      "inputs": {
+        "flake-compat": "flake-compat",
+        "flake-utils": "flake-utils",
+        "gitignore": "gitignore",
+        "nixpkgs": "nixpkgs_3",
+        "nixpkgs-stable": "nixpkgs-stable"
+      },
+      "locked": {
+        "lastModified": 1712579741,
+        "narHash": "sha256-igpsH+pa6yFwYOdah3cFciCk8gw+ytniG9quf5f/q84=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "70f504012f0a132ac33e56988e1028d88a48855c",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
     "root": {
       "inputs": {
         "fenix": "fenix",
         "nixpkgs": "nixpkgs_2",
-        "systems": "systems"
+        "pre-commit-hooks": "pre-commit-hooks",
+        "systems": "systems_2"
       }
     },
     "rust-analyzer-src": {
@@ -77,6 +187,21 @@
       }
     },
     "systems": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "systems_2": {
       "locked": {
         "lastModified": 1689347949,
         "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
diff --git a/flake.nix b/flake.nix
index bfd6561..e645270 100644
--- a/flake.nix
+++ b/flake.nix
@@ -5,6 +5,7 @@
     systems.url = "github:nix-systems/default-linux";
     nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
     fenix.url = "github:nix-community/fenix/monthly";
+    pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix";
   };
 
   outputs = {
@@ -12,7 +13,8 @@
     systems,
     nixpkgs,
     fenix,
-  } @ inputs: let
+    pre-commit-hooks,
+  }: let
     eachSystem = nixpkgs.lib.genAttrs (import systems);
     pkgsFor = eachSystem (system:
       import nixpkgs {
@@ -22,7 +24,7 @@
   in {
     packages = eachSystem (system: let
       pkgs = nixpkgs.legacyPackages.${system};
-      version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
+      inherit ((builtins.fromTOML (builtins.readFile ./Cargo.toml)).package) version;
     in {
       default = pkgsFor.${system}.rustPlatform.buildRustPackage {
         pname = "forcebot_rs";
@@ -40,8 +42,23 @@
         doCheck = false;
       };
     });
+    checks = eachSystem (system: {
+      pre-commit-check = pre-commit-hooks.lib.${system}.run {
+        src = ./.;
+        hooks = {
+          # rust
+          rustfmt.enable = true;
+          clippy.enable = true;
+          # nix
+          statix.enable = true;
+          alejandra.enable = true;
+          deadnix.enable = true;
+        };
+      };
+    });
     devShells = eachSystem (system: {
       default = pkgsFor.${system}.mkShell {
+        inherit (self.checks.${system}.pre-commit-check) shellHook;
         packages = with pkgsFor.${system}; [
           nil
           alejandra
diff --git a/nix/module.nix b/nix/module.nix
index b615be1..cdc3706 100644
--- a/nix/module.nix
+++ b/nix/module.nix
@@ -17,7 +17,7 @@ in {
 
     package = mkOption {
       type = types.package;
-      default = self.packages.${system}.default;
+      inherit (self.packages.${system}) default;
     };
   };
 
diff --git a/statix.toml b/statix.toml
new file mode 100644
index 0000000..fbe25a9
--- /dev/null
+++ b/statix.toml
@@ -0,0 +1,3 @@
+disabled = []
+nix_version = '2.4'
+ignore = ['.direnv']

From dd2670c7664410c4e31ddc4cbd01675523823fd3 Mon Sep 17 00:00:00 2001
From: WoodpeckerCI <woodpecker@flake.sh>
Date: Tue, 9 Apr 2024 01:02:55 +0000
Subject: [PATCH 90/98] flake.lock: update

---
 flake.lock | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flake.lock b/flake.lock
index cf7dd31..7da4bc6 100644
--- a/flake.lock
+++ b/flake.lock
@@ -109,11 +109,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1712543224,
-        "narHash": "sha256-9RSfZL1TKYdGxZwgDxwtBtsKMGR4Zgn+DAnF9s71/lU=",
+        "lastModified": 1712573573,
+        "narHash": "sha256-xxon7WwNm4/EadMKg1eF40/5s0O78nXUy2ILZt6vT7E=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "b0dab7cc34ef4d8a1b2de36178da801090bcb271",
+        "rev": "0d28066770464d19d637f6e8e42e8688420b6ac6",
         "type": "github"
       },
       "original": {

From 74d938751fd44234057a1882e1850a348f83d7fd Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Tue, 9 Apr 2024 10:00:01 -0400
Subject: [PATCH 91/98] cucked promote alt

---
 src/core/identity.rs | 96 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 81 insertions(+), 15 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 726bbdf..a6e623d 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -8,6 +8,7 @@ use std::sync::Arc;
 
 use tokio::sync::RwLock;
 
+use tokio::time::{sleep,Duration};
 use twitch_irc::message::PrivmsgMessage;
 
 use casual_logger::Log;
@@ -59,7 +60,10 @@ pub async fn init(mgr: Arc<ModulesManager>) {
     let tempb = BotCommand {
         module: BotModule(String::from("identity")),
         command: String::from("promote"), // command call name
-        alias: vec![],                    // String of alternative names
+        alias: vec![
+            "cucked".to_string(),
+            "cuck".to_string(),
+        ],                    // String of alternative names
         exec_body: actions_util::asyncbox(cmd_promote),
         help: String::from("promote"),
         required_roles: vec![
@@ -164,7 +168,7 @@ async fn cmd_promote(params : ExecBodyParams) {
 
     let mut argv = params.msg.message_text.split(' ');
 
-    argv.next(); // Skip the command name
+    let cmdname = argv.next(); // Skip the command name
 
     let arg1 = argv.next();
 
@@ -202,7 +206,7 @@ async fn cmd_promote(params : ExecBodyParams) {
     // [x] 1. Get trgusr (regardless of -admin flag)
 
     // let targetusr = if arg1 == Some("-admin") { arg2 } else { arg1 };
-    let targetusr = if 
+    let mut targetusr = if 
             arg1 == Some("-admin") 
             || arg1 == Some("-v") 
             || arg1 == Some("-vip") 
@@ -222,6 +226,50 @@ async fn cmd_promote(params : ExecBodyParams) {
             }
             else { arg1 };
 
+
+    // [x] Check if target is an existing user
+    targetusr = if let Some(chkusr) = targetusr {
+        match twitch_irc::validate::validate_login(chkusr.to_lowercase().as_str()) {
+            Ok(_) => Some(chkusr),
+            Err(_) => None,
+        }
+    } else { None } ;
+
+
+    // [x] Check if cmd passed is cucked, then go through special cucked handling
+    if let Some(cmd_to_check) = cmdname {
+        if cmd_to_check.to_lowercase() == String::from(botlock.get_prefix()) + "cucked" 
+        || cmd_to_check.to_lowercase() == String::from(botlock.get_prefix()) + "cuck"
+        {
+
+            let idlock = botlock.botmgrs.identity.read().await;
+            let senderroles = idlock.getspecialuserroles(sendername.clone(), Some(Channel(targetchnl.to_lowercase()))).await;
+
+            if senderroles.contains(&UserRole::BotAdmin) && targetusr.is_none() {
+                targetusr = Some(sendername.as_str())
+            }
+
+            botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                "uuh ".to_string()
+                ),
+            params.clone(),
+            ).await;
+
+            sleep(Duration::from_secs_f64(1.0)).await;
+
+            
+            botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
+                "... ".to_string()
+                ),
+            params.clone(),
+            ).await;
+
+            sleep(Duration::from_secs_f64(2.0)).await;
+
+        }
+    }
+
+
     // [x] 2. promote trguser
 
     // [x] Get a required lock first
@@ -272,14 +320,23 @@ async fn cmd_promote(params : ExecBodyParams) {
     // [x] 3. Output resulting change
 
     let outmsg = match rslt {
-        ChangeResult::Success(a) => {
-            format!("o7 Successfully promoted : {a}")
+        ChangeResult::Success(rsltstr) => {
+            format!("o7 Successfully promoted {} : {}",
+            targetusr.unwrap().to_string(),
+            rsltstr
+            )
         }
-        ChangeResult::Failed(a) => {
-            format!("PoroSad failed to promote : {a}")
+        ChangeResult::Failed(rsltstr) => {
+            format!("PoroSad failed to promote {} : {}",
+            targetusr.unwrap().to_string(),
+            rsltstr
+            )
         }
-        ChangeResult::NoChange(a) => {
-            format!("uuh No Promotion Change : {a}")
+        ChangeResult::NoChange(rsltstr) => {
+            format!("uuh No Promotion Change {} : {}",
+            targetusr.unwrap().to_string(),
+            rsltstr
+            )
         }
     };
 
@@ -499,14 +556,23 @@ async fn cmd_demote(params : ExecBodyParams) {
      */
 
     let outmsg = match rslt {
-        ChangeResult::Success(a) => {
-            format!("o7 Successfully demoted : {a}")
+        ChangeResult::Success(rsltstr) => {
+            format!("o7 Successfully demoted {} : {}",
+            targetusr.unwrap().to_string(),
+            rsltstr
+            )
         }
-        ChangeResult::Failed(a) => {
-            format!("PoroSad failed to demote : {a}")
+        ChangeResult::Failed(rsltstr) => {
+            format!("PoroSad failed to demote {} : {}",
+            targetusr.unwrap().to_string(),
+            rsltstr
+            )
         }
-        ChangeResult::NoChange(a) => {
-            format!("uuh No Demotion Change : {a}")
+        ChangeResult::NoChange(rsltstr) => {
+            format!("uuh No Demotion Change {} : {}",
+            targetusr.unwrap().to_string(),
+            rsltstr
+            )
         }
     };
 

From 16c6b0eebb3670fd398c4f8eb0d085faa2eb6b69 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Tue, 9 Apr 2024 12:32:02 -0400
Subject: [PATCH 92/98] self-invoking identity methods

---
 src/core/identity.rs | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index a6e623d..59f6eed 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -255,16 +255,16 @@ async fn cmd_promote(params : ExecBodyParams) {
             params.clone(),
             ).await;
 
-            sleep(Duration::from_secs_f64(1.0)).await;
+            sleep(Duration::from_secs_f64(2.0)).await;
 
             
             botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif(
-                "... ".to_string()
+                "... chatter getting cucked ...".to_string()
                 ),
             params.clone(),
             ).await;
 
-            sleep(Duration::from_secs_f64(2.0)).await;
+            sleep(Duration::from_secs_f64(1.0)).await;
 
         }
     }
@@ -608,6 +608,8 @@ async fn getroles(params : ExecBodyParams) {
 
      */
 
+    let sendername = params.msg.clone().sender.name;
+
 
     let mut argv = params.msg.message_text.split(' ');
 
@@ -615,11 +617,17 @@ async fn getroles(params : ExecBodyParams) {
 
     let arg1 = argv.next();
 
-    let targetuser = match arg1 {
-        None => return, // exit if no arguments
+    let mut targetuser = match arg1 {
+        // None => return, // exit if no arguments
+        None => sendername.as_str(), // self-invoke in this case
         Some(arg) => arg,
     };
 
+    targetuser = match twitch_irc::validate::validate_login(targetuser.to_lowercase().as_str()) {
+        Ok(_) => targetuser,
+        Err(_) => sendername.as_str(), // self-invoke in this case
+    };
+
     let arg2 = argv.next();
 
     let targetchnl = arg2;
@@ -703,7 +711,9 @@ async fn getroles(params : ExecBodyParams) {
             params.msg.channel_login.to_lowercase(),
         ))) || sproles.contains(&UserRole::BotAdmin)
         {
-            outmsg += format!("Target chatter's user roles are : {:?}", sproles).as_str();
+            // targetuser
+            // outmsg += format!("Target chatter's user roles are : {:?}", sproles).as_str();
+            outmsg += format!("{}'s user roles are : {:?}", targetuser, sproles).as_str();
         }
         outmsg
     } else if sproles.contains(&UserRole::Mod(Channel(
@@ -712,9 +722,10 @@ async fn getroles(params : ExecBodyParams) {
         params.msg.channel_login.to_lowercase(),
     ))) || sproles.contains(&UserRole::BotAdmin)
     {
-        format!("Target chatter's user roles are : {:?}", sproles)
+        // format!("Target chatter's user roles are : {:?}", sproles)
+        format!("{}'s user roles are : {:?}", targetuser, sproles)
     } else {
-        "Target chatter has no special roles LULE ".to_string()
+        format!("{} has no special roles LULE ",targetuser)
     };
 
     botlog::debug(

From dfb37717b38cec08ad96faad8454d7dd81852ef7 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Tue, 9 Apr 2024 12:36:46 -0400
Subject: [PATCH 93/98] clippy

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

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 59f6eed..0e092e0 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -322,19 +322,19 @@ async fn cmd_promote(params : ExecBodyParams) {
     let outmsg = match rslt {
         ChangeResult::Success(rsltstr) => {
             format!("o7 Successfully promoted {} : {}",
-            targetusr.unwrap().to_string(),
+            targetusr.unwrap(),
             rsltstr
             )
         }
         ChangeResult::Failed(rsltstr) => {
             format!("PoroSad failed to promote {} : {}",
-            targetusr.unwrap().to_string(),
+            targetusr.unwrap(),
             rsltstr
             )
         }
         ChangeResult::NoChange(rsltstr) => {
             format!("uuh No Promotion Change {} : {}",
-            targetusr.unwrap().to_string(),
+            targetusr.unwrap(),
             rsltstr
             )
         }
@@ -558,19 +558,19 @@ async fn cmd_demote(params : ExecBodyParams) {
     let outmsg = match rslt {
         ChangeResult::Success(rsltstr) => {
             format!("o7 Successfully demoted {} : {}",
-            targetusr.unwrap().to_string(),
+            targetusr.unwrap(),
             rsltstr
             )
         }
         ChangeResult::Failed(rsltstr) => {
             format!("PoroSad failed to demote {} : {}",
-            targetusr.unwrap().to_string(),
+            targetusr.unwrap(),
             rsltstr
             )
         }
         ChangeResult::NoChange(rsltstr) => {
             format!("uuh No Demotion Change {} : {}",
-            targetusr.unwrap().to_string(),
+            targetusr.unwrap(),
             rsltstr
             )
         }

From 4b849cfed64984355a8141bb245db3d7c5ac378a Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Tue, 9 Apr 2024 12:51:53 -0400
Subject: [PATCH 94/98] comments cleanup

---
 src/core/identity.rs | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 42bc4c7..effb317 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -15,21 +15,9 @@ use dotenv::dotenv;
 use std::env;
 
 fn adminvector() -> Vec<String> {
-    // vec![String::from("ModulatingForce")]
-    // //vec![]
     dotenv().ok();
     let mut admins = Vec::new();
 
-    // for admin in env::var("bot_admins").unwrap().split(',') {
-    //     admins.push(String::from(admin))
-    // }
-
-    // 03.17 - Forcen - Suggesting below instead : 
-    /*
-        - this will push only if env::var() returns Ok() ; 
-            otherwise (like in Err(_)) do nothing
-     */
-
     if let Ok(value) = env::var("bot_admins") {
         for admin in value.split(',') {
             admins.push(String::from(admin))        

From f86f48178d1a522b1d0f1c89133bb394450221e7 Mon Sep 17 00:00:00 2001
From: notohh <github@notohh.dev>
Date: Tue, 9 Apr 2024 13:27:25 -0400
Subject: [PATCH 95/98] ci: fix branch naming

---
 .woodpecker/cargo-checks.yml | 2 +-
 .woodpecker/flake-update.yml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.woodpecker/cargo-checks.yml b/.woodpecker/cargo-checks.yml
index 1d698f2..fa5ecae 100644
--- a/.woodpecker/cargo-checks.yml
+++ b/.woodpecker/cargo-checks.yml
@@ -1,5 +1,5 @@
 when:
-  branch: main
+  branch: master
   event: [push, pull_request]
   path:
     include:
diff --git a/.woodpecker/flake-update.yml b/.woodpecker/flake-update.yml
index 56c672a..37d88de 100644
--- a/.woodpecker/flake-update.yml
+++ b/.woodpecker/flake-update.yml
@@ -37,7 +37,7 @@ steps:
       owner: ${CI_REPO_OWNER}
       repo: ${CI_REPO_NAME}
       branch: flake-lock-update
-      base_branch: main
+      base_branch: master
       pr_title: "flake.lock: update"
       pr_body: PR automatically created by Woodpecker CI
       close_pr_if_empty: true

From 7f49693a942366a9efe05215e16629ae1b872b58 Mon Sep 17 00:00:00 2001
From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com>
Date: Tue, 9 Apr 2024 13:47:06 -0400
Subject: [PATCH 96/98] clippy

---
 src/core/identity.rs | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/core/identity.rs b/src/core/identity.rs
index 5f7fac1..61c09dc 100644
--- a/src/core/identity.rs
+++ b/src/core/identity.rs
@@ -21,9 +21,6 @@ use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesMana
 use dotenv::dotenv;
 use std::env;
 
-use dotenv::dotenv;
-use std::env;
-
 fn adminvector() -> Vec<String> {
     dotenv().ok();
     let mut admins = Vec::new();

From 55aeaa7fc15c124ec2d0923aa5a547125bda0452 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Tue, 9 Apr 2024 16:22:11 -0300
Subject: [PATCH 97/98] changed reply message on thisguy

---
 src/custom/thisguy.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index 052f601..8616580 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -4,6 +4,7 @@ use crate::core::botlog;
 use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
 use crate::core::identity::UserRole::*;
 use rand::Rng;
+use twitch_irc::message::ReplyToMessage;
 use std::sync::Arc;
 use tokio::time::{sleep, Duration};
 const OF_CMD_CHANNEL:Channel = Channel(String::new());
@@ -34,7 +35,11 @@ async fn tsg(params: ExecBodyParams) {
     botlock
         .botmgrs
         .chat
-        .say_in_reply_to(&params.msg, a, params.clone())
+        .say_in_reply(
+            Channel(params.clone().msg.channel_login().to_string()),
+             a,
+              params.clone()
+            )
         .await;
     sleep(Duration::from_secs_f64(0.5)).await;
 }

From e41f7b0524c19ebf321bc3455125cddd333e7214 Mon Sep 17 00:00:00 2001
From: haruyuumei <luzivotto.erick@gmail.com>
Date: Tue, 9 Apr 2024 16:44:58 -0300
Subject: [PATCH 98/98] warning changed

---
 src/custom/thisguy.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/custom/thisguy.rs b/src/custom/thisguy.rs
index 8616580..cc53129 100644
--- a/src/custom/thisguy.rs
+++ b/src/custom/thisguy.rs
@@ -57,6 +57,6 @@ pub async fn init(mgr: &Arc<ModulesManager>) {
             Broadcaster
             ],
     }
-    .add_to_modmgr(Arc::clone(&mgr))
+    .add_to_modmgr(Arc::clone(mgr))
     .await;
 }
\ No newline at end of file