use std::borrow::Borrow; use std::collections::HashMap; use std::error::Error; use crate::core::botmodules::{ModulesManager,Listener,BotModule,BotActionTrait, BotCommand}; use crate::core::botmodules::bot_actions::actions_util; use crate::core::botinstance::{self,BotInstance}; use futures::lock::Mutex; use twitch_irc::message::{Badge, PrivmsgMessage}; use crate::core::botmodules::ChType; use crate::core::botinstance::ArcBox; use std::rc::Rc; use std::cell::RefCell; use std::sync::{Arc}; use tokio::sync::RwLock; use casual_logger::{Level,Log}; use super::botmodules::bot_actions::actions_util::BotAR; fn adminvector() -> Vec { vec![String::from("ModulatingForce")] } // pub fn init(mgr:&mut ModulesManager) pub async fn init(mgr:Arc) { // println!("Went into Identiy Module init"); botinstance::botlog::trace("Went into Identiy Module init", Some("identity.rs > init()".to_string()), None); // let a = actions_util::asyncbox(cmd_promote) ; let tempb = BotCommand { 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(ChType::Channel(String::new())), UserRole::SupMod(ChType::Channel(String::new())), UserRole::Broadcaster, UserRole::BotAdmin, ], }; tempb.add_to_modmgr(Arc::clone(&mgr)).await; async fn cmd_promote(bot:BotAR,msg:PrivmsgMessage) -> () { //println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); // println!("Called cmd promote"); botinstance::botlog::trace("Called cmd promote", Some("identity.rs > cmd_prommote()".to_string()), Some(&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 ` to assign them `BotAdmin` role - `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` */ /* Usage : promote demote promote admin */ // println!("{}",msg.message_text); botinstance::botlog::trace(&format!("{}",msg.message_text), Some("identity.rs > cmd_prommote()".to_string()), None); let mut argv = msg.message_text.split(" "); argv.next(); // Skip the command name let arg1 = argv.next(); let arg2 = argv.next(); let mut sender_badge:Option = None; for b in &msg.badges { if b.name == "moderator" { sender_badge = Some(ChatBadge::Mod); } else if b.name == "broadcaster" { sender_badge = Some(ChatBadge::Broadcaster); } } match arg1 { Some(a1) if a1 == String::from("-admin") => { // - [ ] BotAdmins can promote admin to give BotAdmin UserRole let botlock = bot.read().await; let idlock = botlock.get_identity(); let id = idlock.read().await; // let ta = ta.getspecialuserroles(String::from("Hello"), Some(ChType::Channel(msg.channel_login.to_lowercase()))); // let ta = ta.getspecialuserroles(arg2.unwrap().to_string(), Some(ChType::Channel(msg.channel_login.to_lowercase()))); let rolesfut = id.getspecialuserroles(msg.sender.name.to_lowercase(), Some(ChType::Channel(msg.channel_login.to_lowercase()))); let usrroles = rolesfut.await; // let ta = ta.unwrap(); // let a = ta.read().await; // let ta = *ta; // let ta = *ta; // if let Some(a) = *ta { if usrroles.contains(&UserRole::BotAdmin) { // println!("BotAdmin allowed to promote admin"); botinstance::botlog::debug("BotAdmin allowed to promote admin", Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); { let idlock = Arc::clone(&bot.read().await.get_identity()); // let idlock = idlock.write().await; let idlock = idlock.read().await; // let mut idlock = *idlock; // let ta = idlock.promote(msg.sender.name.to_lowercase(), None, Some(UserRole::BotAdmin)).await; let ta = idlock.promote(arg2.unwrap().to_string().to_lowercase(), None, Some(UserRole::BotAdmin)).await; match ta { ChangeResult::Success(a) => { // println!("Succesfully promoted : {a} ;"); botinstance::botlog::debug(&format!("BotAdmin Successful Promotion : {a}"), Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); let outmsg = "o7 Successfully promoted : ".to_string(); botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await; }, ChangeResult::Failed(a) => { // println!("Failed to promote : {a} ; "); botinstance::botlog::debug(&format!("BotAdmin Failed Promotion : {a}"), Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); let outmsg = "PoroSad failed to promote : ".to_string(); botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await; }, ChangeResult::NoChange(a) => { // println!("No Changes Made : {a} ; "); botinstance::botlog::debug(&format!("BotAdmin No Change in Promotion : {a}"), Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); let outmsg = "uuh No Promotion Change : ".to_string(); botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await; }, } } } } // }, Some(arg1) => { } _ => (), } let arg2 = argv.next(); let targetchnl = arg2; } // BotCommand { // 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(ChType::Channel(String::new())), // UserRole::SupMod(ChType::Channel(String::new())), // UserRole::Broadcaster, // UserRole::BotAdmin, // ], // }.add_to_modmgr(Arc::clone(&mgr)); let tempb = BotCommand { 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(ChType::Channel(String::new())), UserRole::SupMod(ChType::Channel(String::new())), UserRole::Broadcaster, UserRole::BotAdmin, ], }; tempb.add_to_modmgr(Arc::clone(&mgr)).await; // async fn cmd_demote(mut _chat:Arc>,_msg:PrivmsgMessage) { async fn cmd_demote(mut _chat:BotAR,msg:PrivmsgMessage) { // println!("Called cmd demote"); botinstance::botlog::debug("Called cmd demote", Some("identity.rs > cmd_demote()".to_string()), Some(&msg)); } // BotCommand { // 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(ChType::Channel(String::new())), // UserRole::SupMod(ChType::Channel(String::new())), // UserRole::Broadcaster, // UserRole::BotAdmin, // ], // }.add_to_modmgr(Arc::clone(&mgr)); let tempcomm = BotCommand { 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(ChType::Channel(String::new())), UserRole::SupMod(ChType::Channel(String::new())), UserRole::Broadcaster, UserRole::BotAdmin, ], }; tempcomm.add_to_modmgr(Arc::clone(&mgr)).await; // async fn getroles(bot:Arc>,msg:PrivmsgMessage) { async fn getroles(bot:BotAR,msg:PrivmsgMessage) { // println!("Called cmd getroles"); botinstance::botlog::debug("Called cmd getroles", Some("identity.rs > cmd_getroles()".to_string()), Some(&msg)); /* Usage getroles - If channel is provided, provide roles for that channel specifically */ // IN other code areas , I see this // ServerMessage::Privmsg(msg) => { // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); // println!("{}",msg.message_text); let mut argv = msg.message_text.split(" "); // for v in argv { // println!("args : {v}"); // } argv.next(); // Skip the command name let arg1 = argv.next(); // if arg == None { // return ; // Do nothing if no arguments // } let targetuser = match arg1 { None => return , // exit if no arguments Some(arg) => arg, }; // match String::from(arg1) { // a if a == String::from("admin") => (), // _ => (), // } // match argv[1] { // String::from("admin") => (), // } let arg2 = argv.next(); let targetchnl = arg2; // // let a = bot.read().ok().unwrap().get_identity(); // let a = bot.lock().await; // // let a = a.lock().await; // // let a = a.get_identity().await; // let a = a.botmgrs; // // let a = *(*a).lock().await; // let a = *a.lock().await; // let a = a.identity; // let a = *a.lock().await; // let a = bot.clone(); // let a = a.into_inner(); // let a = a.botmgrs; // let a = a.into_inner(); // let a = a.identity; // let a = a.into_inner(); // let a = bot.clone(); // let a = a.lock().await; // let a = a.get_identity(); // let a = a.lock().await; // let a = bot.get_identity(); let botlock = bot.read().await; // println!("botlock read"); botinstance::botlog::trace("botlock read", Some("identity.rs > init > getroles()".to_string()), Some(&msg)); let idlock = botlock.get_identity(); // println!("got identity"); botinstance::botlog::trace("got identity", Some("identity.rs > init > getroles()".to_string()), Some(&msg)); let idlock = idlock.read().await; // <-- 02.12 - Latest where it gest stuck - before or at this point // println!("id lock"); botinstance::botlog::trace("id lock", Some("identity.rs > init > getroles()".to_string()), Some(&msg)); let sproles = match targetchnl { None => { // let bot = Rc::clone(&bot); //let bot = Arc::clone(&bot); // let a = bot.botmgrs.identity.getspecialuserroles(String::from(targetuser),None); // let a = Arc::try_unwrap(bot).ok().unwrap().into_inner().ok().unwrap(); // let a = Arc::try_unwrap(bot.clone()).ok().unwrap().into_inner(); // let a = a.botmgrs.identity.getspecialuserroles(String::from(targetuser),None); // let a = a.ok().getspecialuserroles(String::from(targetuser),None); // let a = bot.read().ok().unwrap().rIdentity().getspecialuserroles(String::from(targetuser),None); // println!("Retrieved User Roles >> {:?}",a); // let a = idlock.read().await; // idlock.getspecialuserroles(String::from(targetuser),None).await // [ ] If targetchnl is not provided, default to pulling the current channel idlock.getspecialuserroles(String::from(targetuser),Some(ChType::Channel(msg.channel_login.to_lowercase()))).await }, Some(targetchnl) => { // let bot = Rc::clone(&bot); // let bot = Arc::clone(&bot); // let a = bot.botmgrs.identity.getspecialuserroles(String::from(targetuser), Some(ChType::Channel(String::from(targetchnl)))); // Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner() // let a = Arc::try_unwrap(bot).ok().unwrap().into_inner().ok().unwrap(); // let a = Arc::try_unwrap(bot.clone()).ok().unwrap().into_inner(); // let a = a.botmgrs.identity.getspecialuserroles(String::from(targetuser), Some(ChType::Channel(String::from(targetchnl)))); // let a = bot.read().ok().unwrap().rIdentity().getspecialuserroles(String::from(targetuser),None); // println!("Retrieved User Roles >> {:?}",a); // bot.read().ok().unwrap().rIdentity().getspecialuserroles(String::from(targetuser),None) // let a = a.read().await; // [ ] If caller is not a BotAdmin, they can only pull those related to the current channel for the target user // [ ] If caller is a BotAdmin, allow & return for target channel // let mut sender_badge:Option = None; // for b in &msg.badges { // if b.name == "moderator" { // sender_badge = Some(ChatBadge::Mod); // } else if b.name == "broadcaster" { // sender_badge = Some(ChatBadge::Broadcaster); // } // } // match sender_badge { // Some(ChatBadge::Mod) => { // } , // Some(ChatBadge::Broadcaster) => { // } // _ => { // } // } // [x]gets special roles for caller let callersproles = idlock.getspecialuserroles(msg.sender.name.to_lowercase(),Some(ChType::Channel(targetchnl.to_lowercase().to_string()))).await; // idlock.getspecialuserroles(String::from(targetuser),Some(ChType::Channel(targetchnl.to_lowercase().to_string()))).await // let a = callersproles.contains(&UserRole::Mod(ChType::Channel(targetchnl.to_lowercase().to_string()))); if callersproles.contains(&UserRole::Mod(ChType::Channel(targetchnl.to_lowercase().to_string()))) || callersproles.contains(&UserRole::SupMod(ChType::Channel(targetchnl.to_lowercase().to_string()))) || callersproles.contains(&&UserRole::Broadcaster) { idlock.getspecialuserroles(String::from(targetuser),Some(ChType::Channel(targetchnl.to_lowercase()))).await // callersproles } else { // Otherwise, don't get the target channel, return the current channel instead idlock.getspecialuserroles(String::from(targetuser),Some(ChType::Channel(msg.channel_login.to_lowercase()))).await } }, }; // let sproles = idlock.getspecialuserroles(String::from(targetuser),).await; // println!("Retrieved User Roles >> {:?}",sproles); botinstance::botlog::debug(&format!("User roles of Target Chatter >> {:?}",sproles), Some("identity.rs > init > getroles()".to_string()), Some(&msg)); // # I believe at this stage I still have botlock active botinstance::botlog::debug(&format!("Evaluating special roles"), Some("identity.rs > init > getroles()".to_string()), Some(&msg)); // let mut outmsg = String::new(); let sproles = sproles; // let arg2 = arg2.unwrap(); let outmsg = if ((targetuser.to_lowercase() == msg.channel_login.to_lowercase()) && arg2.is_none()) || (arg2.is_some() && arg2.unwrap() == targetuser.to_lowercase()) { // First evaluates if they're broadcaster format!("FeelsWowMan they're the broadcaster ") } else if sproles.contains(&UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase()))) || sproles.contains(&UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase()))) || sproles.contains(&UserRole::BotAdmin) { format!("Target chatter's user roles are : {:?}",sproles) } else { format!("Target chatter has no special roles LULE ") }; // if sproles.contains(&UserRole::Mod(msg.channel_login.to_lowercase())) { // } else if sproles.contains(&UserRole::Mod(msg.channel_login.to_lowercase())) { // } // let outmsg = match sproles // { // // let mut outmsg = String::new(); // Some(sproles) => { // let sproles = sproles.read().await; // format!("Target chatter's user roles are : {:?}",sproles) // } // None => { // // # NOTE : Broadcaster could be included in this // // # below is checking if the provided text includes the username // // let msg = msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase()); // botinstance::botlog::debug(&format!("Evaluating special roles > channel login : {} ; message text : {} ; ",&msg.channel_login,&msg.message_text), // Some("identity.rs > init > getroles()".to_string()), Some(&msg)); // botinstance::botlog::debug(&format!("Evaluating special roles > bool evaluation : {} ", // msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase())), // Some("identity.rs > init > getroles()".to_string()), Some(&msg)); // if msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase()) { // format!("FeelsWowMan they're the broadcaster ") // } else { // format!("Target chatter has no special roles LULE ") // } // } // }; // let a = bot.identity.getuserroles(String::from("ModulatingForce"), Some(ChType::Channel(String::from("ModulatingForcebot")))); // println!("{:?}",a); botinstance::botlog::debug(&format!("Chat Say Reply message : {:?}",outmsg), Some("identity.rs > init > getroles()".to_string()), Some(&msg)); botlock.botmgrs.chat.say_in_reply_to(&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 } // println!("End of Init MOdule add"); botinstance::botlog::trace("End of Init MOdule add", Some("identity.rs > init ".to_string()), None); Log::flush(); } // #[derive(Debug, PartialEq, Eq, Hash, Clone)] // pub enum ChType { // Channel(String), // } #[derive(Debug, PartialEq, Eq , Clone)] pub enum UserRole { Chatter, Mod(ChType), // String specifies Channel SupMod(ChType), // String specifies Channel Broadcaster, BotAdmin, } pub enum Permissible { Allow, Block } #[derive(Clone)] pub struct IdentityManager { // special_roles_users : HashMap>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel // special_roles_users : Arc>>>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel // special_roles_users : Arc>>>, special_roles_users : Arc>>>>>, // parent_mgr : Box, //parent_mgr : Option>, } pub enum ChatBadge { Broadcaster, Mod, } pub enum ChangeResult { Success(String), Failed(String), NoChange(String), } impl IdentityManager { pub fn init() -> IdentityManager { let mut a = HashMap::new(); for admn in adminvector() { a.insert(admn.to_lowercase(),Arc::new(RwLock::new(vec![UserRole::BotAdmin]))); }; IdentityManager { special_roles_users : Arc::new(RwLock::new(a)), //parent_mgr : None, } } // [ ] Maybe I should create a can_user_run version that simply takes PrvMsg, but then calls can_user_run directly // pub fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Result> // pub fn can_user_run_PRVMSG(&self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Permissible // pub async fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Permissible pub async fn can_user_run_PRVMSG(&mut self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> (Permissible,ChangeResult) { // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); // [ ] Check what Badges in PrivmsgMessage // println!{"Checking within PRVMSG"}; botinstance::botlog::debug("Checking within PRVMSG", Some("identity.rs > can_user_run_PRVMSG()".to_string()), Some(&msg)); let mut sender_badge:Option = None; for b in &msg.badges { if b.name == "moderator" { sender_badge = Some(ChatBadge::Mod); } else if b.name == "broadcaster" { sender_badge = Some(ChatBadge::Broadcaster); } } // 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()), sender_badge, cmdreqroles ).await } pub async fn can_user_run(&mut self, usr:String, channelname:ChType, chat_badge:Option, cmdreqroles:Vec // ) -> Result> { ) -> (Permissible,ChangeResult) { // println!{"Checking within can_user_run()"}; botinstance::botlog::debug("Checking within can_user_run()", Some("identity.rs > can_user_run()".to_string()), None); /* canUserRun - Input : usr:String, channelname:ChType, chat_badge:ChatBadge, cmdreqroles:Vec Output : Result> Some Possible outcomes : Ok(Permissible::Allow) , Ok(Permissible::Block) Description For a Given Chatter (with any special ChatBadge) who ran the Command at a Given Channel , check if that user can run the command based on the given cmdreqroles required by the command Inputs and business logic determine if the user can run the command based on the command's required roles */ // Requirements /* [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow) [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) [x] If chatBadge::Mod ... [x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) [x] If not, assign them UserRole::Mod(channelname::ChType) [x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) [x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow) [x] Otherwise, Ok(Permissible::Block) */ // [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow) // let idar = Arc::new(RwLock::new(self)); if cmdreqroles.len() == 0 { // return Ok(Permissible::Allow) return (Permissible::Allow , ChangeResult::NoChange("Command has no required cmdreqroles".to_string())) } let mut modrolechange = 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) Some(ChatBadge::Broadcaster) => { if cmdreqroles.contains(&UserRole::Broadcaster) || cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) || cmdreqroles.contains(&UserRole::SupMod(ChType::Channel(String::new()))) { // return Ok(Permissible::Allow) return (Permissible::Allow , ChangeResult::NoChange("Broadcaster Role".to_string())) } }, // [x] If chatBadge::Mod ... // [x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) // [x] If not, assign them UserRole::Mod(channelname::ChType) Some(ChatBadge::Mod) => { // println!("Mod Chatbadge detected"); botinstance::botlog::info("Mod Chatbadge detected", Some("identity.rs > can_user_run()".to_string()), None); // println!("debug special roles : {:?}",self.special_roles_users); // println!("debug usr : {}",&usr.to_lowercase()); // let Some((k,v)) = self.special_roles_users.get_key_value(usr); // match self.special_roles_users.get_mut(&usr.to_lowercase()) { // match self.special_roles_users.get(&usr.to_lowercase()) { // println!("Creating clone"); botinstance::botlog::trace("Creating clone", Some("identity.rs > can_user_run()".to_string()), None); let roleslock = Arc::clone(&(*self).special_roles_users); // println!("Read lock on : Special_Roles_User"); // <-- after this is slightly different between working and problem botinstance::botlog::trace("Read lock on : Special_Roles_User", Some("identity.rs > can_user_run()".to_string()), None); let mut roleslock = roleslock.write().await; match (*roleslock).get(&usr.to_lowercase()) { Some(usrroles) if usrroles.read().await.contains(&UserRole::Mod(channelname.clone())) || usrroles.read().await.contains(&UserRole::SupMod(channelname.clone())) => { // <-- working got to this point // println!("contains mod : {}", usrroles.read().await.contains(&UserRole::Mod(channelname.clone()))); // println!("contains supmod : {}", usrroles.read().await.contains(&UserRole::SupMod(channelname.clone()))); // Do nothing when theh have a mod badge and have either a supmod or mod badge for the channel // println!("Already a mod in roles"); botinstance::botlog::trace("Already a mod in roles", Some("identity.rs > can_user_run()".to_string()), None); } _ => { // In the event they have a mod badge , are running a bot command, but don't have a channel mod role yet... // println!("lock created > adding with a mod role o7"); botinstance::botlog::trace("lock created > adding with a mod role o7", Some("identity.rs > can_user_run()".to_string()), None); // botinstance::botlog::notice("Assigning ModRole to Chatter", // Some("identity.rs > can_user_run()".to_string()), None); let mut roleslock = roleslock; let mut a = roleslock.get_mut(&usr.to_lowercase()).unwrap(); let mut alock = a.write().await; alock.push(UserRole::Mod(channelname.clone())); modrolechange = ChangeResult::Success("Auto Promoted Mod".to_string()); // alock.get_mut(&usr.to_lowercase()) // .get_or_insert_with(|| UserRole::Mod(channelname.clone())) // // .expect("ERROR") // .unwrap() // .write().await // // .get_mut() // .push(UserRole::Mod(channelname.clone())); } // <-- I'm assuming problem got to here } }, _ => (), // Don't handle other roles here } // [x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) // println!("cmd required roles : {:?}",cmdreqroles); botinstance::botlog::trace(&format!("cmd required roles : {:?}",cmdreqroles), Some("identity.rs > can_user_run()".to_string()), None); if cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) { // match self.special_roles_users.get(&channelname) { // Some(usrroles) => {}, // None => (), // } // println!("Command requires Mod Role"); botinstance::botlog::trace("Command requires Mod Role", Some("identity.rs > can_user_run()".to_string()), None); if let Some(a) = (&*self).special_roles_users.read().await.get(&usr.to_lowercase()) { // println!("Special roles found for user"); botinstance::botlog::trace("Special roles found for user", Some("identity.rs > can_user_run()".to_string()), None); if a.read().await.contains(&UserRole::Mod(channelname.clone())) || a.read().await.contains(&UserRole::SupMod(channelname.clone())){ // return Ok(Permissible::Allow); // println!("Special roles found for user : A mod idenfified "); botinstance::botlog::trace("> Special Role Identified : Mod ", Some("identity.rs > can_user_run()".to_string()), None); return (Permissible::Allow , modrolechange) } } } // [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 let Some(a) = (&*self).special_roles_users.read().await.get(&usr.to_lowercase()) { if a.read().await.contains(&UserRole::SupMod(channelname.clone())) { // return Ok(Permissible::Allow); return (Permissible::Allow,modrolechange) } } } // [x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow) // println!("Eval cmdreqroles with botadmin : {}",cmdreqroles.contains(&UserRole::BotAdmin)); botinstance::botlog::trace(&format!("Eval cmdreqroles with botadmin : {}",cmdreqroles.contains(&UserRole::BotAdmin)), Some("identity.rs > can_user_run()".to_string()), None); if cmdreqroles.contains(&UserRole::BotAdmin) { // println!("special roles get : {:?}",(&*self).special_roles_users.read().await.get(&usr.to_lowercase())); botinstance::botlog::trace(&format!("special roles get : {:?}",(&*self).special_roles_users.read().await.get(&usr.to_lowercase())), Some("identity.rs > can_user_run()".to_string()), None); if let Some(a) = (&*self).special_roles_users.read().await.get(&usr.to_lowercase()) { println!("special roles contains BotAdmin: {}",a.read().await.contains(&UserRole::BotAdmin)); botinstance::botlog::trace(&format!("special roles contains BotAdmin: {}",a.read().await.contains(&UserRole::BotAdmin)), Some("identity.rs > can_user_run()".to_string()), None); if a.read().await.contains(&UserRole::BotAdmin) { // return Ok(Permissible::Allow); return (Permissible::Allow,modrolechange) } } } (Permissible::Block , ChangeResult::NoChange("Not any permissiable condition".to_string())) } // pub async fn promote(&mut self,trgchatter:String,channel:Option,trg_role:Option) -> ChangeResult { pub async fn promote(&self,trgchatter:String,channel:Option,trg_role:Option) -> ChangeResult { // Note : If channel is none, getspecialuserroles() returns all roles for the user // let chatterroles = self.getspecialuserroles(trgchatter, channel); // let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()); // let chatterroles = *self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; // let chatterroles = chatterroles.lock().await; // // let chatterroles = *chatterroles; // let chatterroles = chatterroles.unwrap(); let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; // let chatterroles = chatterroles.lock().await; // let chatterroles = *chatterroles; // let chatterroles = chatterroles.unwrap(); // let emptyvec = vec![]; // let chatterroles = match chatterroles { // Some(a) => a, // _ => &(emptyvec), // }; // let chatterroles = chatterroles.unwrap(); // let chatterroles = chatterroles.read().await; //let rolemap = &(*chatterroles); let rolemap = chatterroles; match trg_role { Some(UserRole::Mod(a)) => { if let Some(trg_chnl) = channel.clone() { let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; let rolemap = chatterroles; // let rolemap = rolemap.unwrap(); if rolemap.contains(&UserRole::Mod(trg_chnl.clone())) { return ChangeResult::NoChange(String::from("Target User already has Target Role")); } // # otherwise, trg_role for the given chnl is not assigned to the trgchatter // chatterroles.push(UserRole::Mod(trg_chnl.clone())); // let a = self.special_roles_users; // let b = a.write().await; // // let c = b.get_mut(&trgchatter); // let c = (*b).; // [x] (!!) AROUND HERE - check if the user exists first, and at least add the user as we're promoting anyway { let mut srulock = self.special_roles_users.write().await; srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())), Some("identity.rs > promote()".to_string()), None); Log::flush(); } { let mut srulock = self.special_roles_users.write().await; srulock .get_mut(&trgchatter) .expect("Error getting roles") // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at .write().await .push(UserRole::Mod(trg_chnl)); botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",srulock.entry(trgchatter.clone())), Some("identity.rs > promote()".to_string()), None); Log::flush(); } return ChangeResult::Success(String::from("Promotion Successful")); } }, Some(UserRole::SupMod(a)) => (), Some(UserRole::BotAdmin) => { let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; let rolemap = chatterroles; botinstance::botlog::trace(&format!("Target Role : BotAdmin"), Some("identity.rs > promote()".to_string()), None); // [x] 1. Check their roles first if they already have botadmin // [x] 2. Know that prior to promote() , BotAdmins should have been validated before being able to pass the BotAdmin target // [x] 1. Check target chatter's roles first if they already have botadmin botinstance::botlog::trace(&format!("Eval rolemap.contains(BotAdmin) : {}",rolemap.contains(&UserRole::BotAdmin)), Some("identity.rs > promote()".to_string()), None); botinstance::botlog::trace(&format!("Eval rolemap.contains(BotAdmin) > Rolemap : {:?}",rolemap), Some("identity.rs > promote()".to_string()), None); // [ ] (!) This seems to be an issue - rolemap by this point is blank if rolemap.contains(&UserRole::BotAdmin) { return ChangeResult::NoChange(String::from("Target User already has Target Role")); } // # otherwise, trg_role for the given chnl is not assigned to the trgchatter // chatterroles.push(UserRole::Mod(trg_chnl.clone())); // [x] (!!) AROUND HERE - check if the user exists first, and at least add the user as we're promoting anyway { let mut srulock = self.special_roles_users.write().await; srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())), Some("identity.rs > promote()".to_string()), None); Log::flush(); } { let mut srulock = self.special_roles_users.write().await; srulock .get_mut(&trgchatter) // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at .expect("Error getting roles") .write().await .push(UserRole::BotAdmin); botinstance::botlog::trace(&format!("SRLOCK - 2nd write > {:?}",srulock.entry(trgchatter.clone())), Some("identity.rs > promote()".to_string()), None); Log::flush(); } botinstance::botlog::trace(&format!("Target Role : BotAdmin >> Successful"), Some("identity.rs > promote()".to_string()), None); return ChangeResult::Success(String::from("Promotion Successful")); }, Some(_) => (), None => (), } // match chatterroles { // Some(chatterroles) => { // // [x] chatter already has the target role // if chatterroles.contains(&trg_role) { // return ChangeResult::NoChange(String::from("Target User already has Target Role")); // } // // By this point, chatteroles does not contain target role // // match trgRole { // // Some(trgRole) => { // // match trgRole { // // UserRole::Mod(a) => { // // }, // // UserRole::SupMod(a) => (), // // UserRole::BotAdmin => (), // // _ => (), // <-- do nothing with al other options // // } // // }, // // None => { // // /* // // - If trgRole is None , then promote by implicit rules . For example, // // - For UserRoles without Mod or SupMod & Caller is SupMod | Broadcaster | BotAdmin > To Mod // // - For Mod & Caller is SupMod | Broadcaster | BotAdmin > To SupMod // // - For UserRoles without BotAdmin & Caller is BotAdmin > To BotAdmin // // */ // // }, // // } // // let trgRole = match trgRole { // // Some(UserRole::Mod(a)) => a, // // Some(UserRole::SupMod(a)) => a, // // Some(UserRole::BotAdmin) => UserRole::BotAdmin, // // None => { // // /* // // - If trgRole is None , then promote by implicit rules . For example, // // - For UserRoles without Mod or SupMod & Caller is SupMod | Broadcaster | BotAdmin > To Mod // // - For Mod & Caller is SupMod | Broadcaster | BotAdmin > To SupMod // // - For UserRoles without BotAdmin & Caller is BotAdmin > To BotAdmin // // */ // // }, // // }; // // if let Some(trgRole) = trgRole { // // // [x] chatter already has the target role // // if chatterroles.contains(&trgRole) { // // return ChangeResult::NoChange(String::from("Target User already has Target Role")); // // } // // // [ ] trgRole should be assigned based on the input channel // // let roletoassign = UserRole:: // // } // }, // _ => (), // } ChangeResult::Success(String::from("TEST > Promotion Successful")) } pub fn demote(self,trgchatter:String,channel:Option,trgRole:Option) -> ChangeResult { ChangeResult::Success(String::from("TEST > Promotion Successful")) } // pub async fn getspecialuserroles(&self,chattername:String,channel:Option) -> Option>>> { pub async fn getspecialuserroles(&self,chattername:String,channel:Option) -> Vec { /* Note : Ideally this be called for a given chatter name ? */ // [ ] !!! TODO: I don't think below is evaluating by given channel botinstance::botlog::debug(&format!("IN VARS > chattername {} ; channel {:?}", chattername,channel), Some("IdentityManager > getspecialuserroles()".to_string()), None); // resulting vector let mut evalsproles = vec![]; let chattername = chattername.to_lowercase(); // Checks if broadcaster let channel_out = match channel { Some(channel_tmp) => { match channel_tmp { ChType::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)) }, // _ => () } } None => None, }; let rolesa = Arc::clone(&self.special_roles_users); let a = rolesa.read().await; // let a = Arc::clone(a) let a = a; let vecroles = &(*a); let vecroles = vecroles.get(&chattername); match vecroles { Some(a) => { // [ ] This needs to take the user roles for the user, then yield only the one for the channel if channel is explicitely provided // Some(Arc::clone(a)) match channel_out { Some(channel) => { // let eval = a.read().await.contains(&UserRole::Mod(channel)); // let eval = a.read().await.contains(&UserRole::SupMod(channel)); botinstance::botlog::debug(&format!("INTERNAL > All Roles found {:?}", &a), Some("IdentityManager > getspecialuserroles()".to_string()), None); // a.read().await.contains(&UserRole::BotAdmin) botinstance::botlog::trace(&format!("INTERNAL > eval special roles contains botadmin : {:?}", a.read().await.contains(&UserRole::BotAdmin)), Some("IdentityManager > getspecialuserroles()".to_string()), None); if a.read().await.contains(&UserRole::BotAdmin) { evalsproles.push(UserRole::BotAdmin); } if a.read().await.contains(&UserRole::Mod(channel.clone())) { evalsproles.push(UserRole::Mod(channel.clone())); } if a.read().await.contains(&UserRole::SupMod(channel.clone())) { evalsproles.push(UserRole::SupMod(channel.clone())); } // else {}; } None => { // here , do nothing if the channel not provided // [ ] TODO : Future is to provide all maybe ? // ... no I think missing this is an issue for when the flag is -admin and channel is None? // // => 02.13 - Decided That None is provided as a Channel, we can output non-channel related roles like BotAdmin if a.read().await.contains(&UserRole::BotAdmin) { evalsproles.push(UserRole::BotAdmin); } } } }, None => { // here, the user has no special listed roles. Note though Broadcaster is not stored in special roles // Do nothing in this case // There may be an issue if the chattername does not exist at the moment in special_roles_users // In this case, evalsproles would only contain Broadcaster flags if any }, } botinstance::botlog::debug(&format!("OUT > evalsproles {:?}", &evalsproles), Some("IdentityManager > getspecialuserroles()".to_string()), None); return evalsproles; } }