forcebot_rs/src/core/identity.rs

2901 lines
120 KiB
Rust
Raw Normal View History

2024-02-04 14:28:37 -05:00
use std::borrow::Borrow;
2024-01-29 06:18:27 -05:00
use std::collections::HashMap;
2024-01-29 12:41:26 -05:00
use std::error::Error;
2024-01-29 11:09:33 -05:00
use crate::core::botmodules::bot_actions::actions_util;
2024-02-25 10:40:54 -05:00
use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager};
2024-01-29 11:09:33 -05:00
2024-02-25 10:40:54 -05:00
use crate::core::botinstance::{self, botlog, BotInstance, ChType};
2024-02-04 14:28:37 -05:00
use futures::lock::Mutex;
2024-01-29 22:57:07 -05:00
use twitch_irc::message::{Badge, PrivmsgMessage};
2024-01-29 11:09:33 -05:00
// use crate::core::botmodules::ChType;
2024-01-29 12:41:26 -05:00
2024-02-04 14:28:37 -05:00
use crate::core::botinstance::ArcBox;
use std::cell::RefCell;
2024-02-25 10:40:54 -05:00
use std::rc::Rc;
2024-02-04 14:28:37 -05:00
2024-02-19 21:04:01 -05:00
use std::sync::Arc;
2024-02-12 05:25:38 -05:00
use tokio::sync::RwLock;
2024-02-25 10:40:54 -05:00
use casual_logger::{Level, Log};
2024-02-04 14:28:37 -05:00
2024-02-12 01:25:12 -05:00
use super::botmodules::bot_actions::actions_util::BotAR;
2024-01-29 06:18:27 -05:00
fn adminvector() -> Vec<String> {
vec![String::from("ModulatingForce")]
//vec![]
2024-01-29 06:18:27 -05:00
}
2024-02-04 14:28:37 -05:00
// pub fn init(mgr:&mut ModulesManager)
2024-02-25 10:40:54 -05:00
pub async fn init(mgr: Arc<ModulesManager>) {
2024-02-13 10:11:49 -05:00
// println!("Went into Identiy Module init");
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
"Went into Identiy Module init",
Some("identity.rs > init()".to_string()),
None,
);
2024-02-12 01:25:12 -05:00
2024-02-12 02:34:32 -05:00
// let a = actions_util::asyncbox(cmd_promote) ;
let tempb = BotCommand {
2024-02-25 10:40:54 -05:00
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,
2024-02-25 10:40:54 -05:00
],
2024-02-12 02:34:32 -05:00
};
2024-02-25 10:40:54 -05:00
2024-02-12 05:25:38 -05:00
tempb.add_to_modmgr(Arc::clone(&mgr)).await;
2024-01-29 11:09:33 -05:00
2024-02-25 10:40:54 -05:00
async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) -> () {
2024-01-29 11:09:33 -05:00
//println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
2024-02-13 10:11:49 -05:00
// println!("Called cmd promote");
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
"Called cmd promote",
Some("identity.rs > cmd_prommote()".to_string()),
Some(&msg),
);
2024-01-29 12:41:26 -05:00
2024-01-31 21:30:08 -05:00
// -- 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
2024-01-30 15:07:40 -05:00
/*
- `promote` / `demote`
- [ ] `SupMod` & `Broadcaster` & `BotAdmin` can run
2024-02-25 10:40:54 -05:00
- [ ] `UserRole`s that can run, can
2024-01-30 15:07:40 -05:00
- [ ] run `promote` on a regular `Chatter` to make them a `Mod`
- [ ] run `demote` on a `Mod` to make them a `Chatter`
2024-02-25 10:40:54 -05:00
- [ ] Only `BotAdmin` can :
2024-01-30 15:07:40 -05:00
- [ ] target themselves to `promote` / `demote` , in the case that they want to make themselves either a `Mod` or `SupMod` for the channel temporarily
2024-02-25 10:40:54 -05:00
- [ ] `promote admin <Chatter>` to assign them `BotAdmin` role
2024-02-14 01:09:55 -05:00
- `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` or `promote` the other way
2024-01-30 15:07:40 -05:00
*/
2024-01-31 21:30:08 -05:00
/*
2024-02-25 10:40:54 -05:00
Usage :
2024-01-31 21:30:08 -05:00
2024-02-14 01:09:55 -05:00
promote <user>
2024-01-31 21:30:08 -05:00
2024-02-25 10:40:54 -05:00
demote <user>
2024-01-31 21:30:08 -05:00
2024-02-14 01:09:55 -05:00
promote -admin <user>
2024-01-31 21:30:08 -05:00
2024-02-25 10:40:54 -05:00
*/
2024-02-04 14:28:37 -05:00
2024-02-13 10:11:49 -05:00
// println!("{}",msg.message_text);
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
&format!("Twich Message > {}", msg.message_text),
Some("identity.rs > cmd_promote()".to_string()),
None,
);
2024-02-13 10:11:49 -05:00
let sendername = msg.clone().sender.name;
2024-02-25 10:40:54 -05:00
let mut argv = msg.message_text.split(" ");
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
argv.next(); // Skip the command name
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
let arg1 = argv.next();
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
let arg2 = argv.next();
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
let mut sender_badge: Option<ChatBadge> = None;
2024-02-25 10:40:54 -05:00
for b in &msg.badges {
if b.name == "moderator" {
sender_badge = Some(ChatBadge::Mod);
} else if b.name == "broadcaster" {
sender_badge = Some(ChatBadge::Broadcaster);
}
}
let targetchnl = msg.channel_login.to_lowercase();
2024-02-25 10:40:54 -05:00
/*
2024-02-25 10:40:54 -05:00
[x] 1. Get trgusr (regardless of -admin flag)
[x] 2. promote trguser
[x] 3. Output resulting change
2024-02-25 10:40:54 -05:00
*/
// [x] 1. Get trgusr (regardless of -admin flag)
2024-02-25 10:40:54 -05:00
let targetusr = if arg1 == Some("-admin") { arg2 } else { arg1 };
2024-02-01 08:40:09 -05:00
// [x] 2. promote trguser
// [x] Get a required lock first
let botlock = bot.read().await;
let id = botlock.get_identity();
let idlock = id.read().await;
let rslt = match targetusr {
Some(targetusr) => {
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("running promote()"),
Some("identity.rs > cmd_promote()".to_string()),
None,
);
Log::flush();
2024-02-25 10:40:54 -05:00
let target_bot_admin_role = if arg1 == Some("-admin") {
Some(UserRole::BotAdmin)
} else {
None
};
2024-02-25 10:40:54 -05:00
idlock
.promote(
sendername.clone(),
&sender_badge,
targetusr.to_string(),
Some(ChType::Channel(targetchnl.clone())),
target_bot_admin_role,
)
.await
}
None => {
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("No Targer User argument"),
Some("identity.rs > cmd_demote()".to_string()),
None,
);
Log::flush();
ChangeResult::NoChange("No Targer User".to_string())
}
};
2024-02-25 10:40:54 -05:00
// [x] 3. Output resulting change
match rslt {
ChangeResult::Success(a) => {
// println!("Succesfully promoted : {a} ;");
let outmsg = &format!("o7 Successfully promoted : {a}");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
outmsg,
Some("identity.rs > cmd_prommote()".to_string()),
Some(&msg),
);
// let outmsg = "o7 Successfully promoted : ".to_string();
2024-02-25 10:40:54 -05:00
botlock
.botmgrs
.chat
.say_in_reply_to(&msg, outmsg.to_string())
.await;
}
ChangeResult::Failed(a) => {
// println!("Failed to promote : {a} ; ");
let outmsg = &format!("PoroSad failed to promote : {a}");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
outmsg,
Some("identity.rs > cmd_prommote()".to_string()),
Some(&msg),
);
// let outmsg = "PoroSad failed to promote : ".to_string();
2024-02-25 10:40:54 -05:00
botlock
.botmgrs
.chat
.say_in_reply_to(&msg, outmsg.to_string())
.await;
}
ChangeResult::NoChange(a) => {
// println!("No Changes Made : {a} ; ");
let outmsg = &format!("uuh No Promotion Change : {a}");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
outmsg,
Some("identity.rs > cmd_prommote()".to_string()),
Some(&msg),
);
// let outmsg = "uuh No Promotion Change : ".to_string();
2024-02-25 10:40:54 -05:00
botlock
.botmgrs
.chat
.say_in_reply_to(&msg, outmsg.to_string())
.await;
}
}
2024-02-25 10:40:54 -05:00
/*
match arg1 {
Some(a1) if a1 == String::from("-admin") => {
// - [x] 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} ;");
let outmsg = &format!("o7 Successfully promoted : {a}");
botinstance::botlog::debug(outmsg,
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.to_string()).await;
},
ChangeResult::Failed(a) => {
// println!("Failed to promote : {a} ; ");
let outmsg = &format!("PoroSad failed to promote : {a}");
botinstance::botlog::debug(outmsg,
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.to_string()).await;
},
ChangeResult::NoChange(a) => {
// println!("No Changes Made : {a} ; ");
let outmsg = &format!("uuh No Promotion Change : {a}");
botinstance::botlog::debug(outmsg,
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.to_string()).await;
},
}
}
} // if usrroles.contains(&UserRole::BotAdmin)
}
// },
Some(arg1) => {
// In the case of promoting another chatter
// Check caller's roles
// Check targer chatter's roles
// - Also check if target chatter alread has target roles
// if caller's role is Broadcaster, SupMod, BotAdmin , they can Promote target Chatters to become Mod (i.e., the target user is not a Mod,SupMod,BotAdmin)
// if caller is BotAdmin, they can promote BotAdmins to Mod
// if caller's role is Broadcaster, BotAdmin, they can Promote target Mod to SupMod
botinstance::botlog::debug(&format!("Evaluating arg1: {arg1}"),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
let idlock = Arc::clone(&bot.read().await.get_identity());
let idlock = idlock.read().await;
// let ta = idlock.promote(msg.sender.name.to_lowercase(), None, Some(UserRole::BotAdmin)).await;
let senderroles = idlock.getspecialuserroles(
msg.sender.name.to_lowercase(),
Some(ChType::Channel(msg.channel_login.to_lowercase()))).await;
let trgusrroles = idlock.getspecialuserroles(
arg1.to_lowercase(),
Some(ChType::Channel(msg.channel_login.to_lowercase()))).await;
botinstance::botlog::debug(&format!("Ready to evaluate sender and targer user roles"),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
botinstance::botlog::trace(&format!("Related Vars : sender roles : {:?} ; targer usr roles : {:?}" ,
senderroles,trgusrroles),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
if ( senderroles.contains(&UserRole::Broadcaster) ||
senderroles.contains(&UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase()))) ||
senderroles.contains(&UserRole::BotAdmin) ) &&
( !trgusrroles.contains(&UserRole::Broadcaster) &&
// !trgusrroles.contains(&UserRole::BotAdmin) && // target users that are BotAdmins can promote themselves to Mod or SupMod
!trgusrroles.contains(&UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase()))) &&
!trgusrroles.contains(&UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase())))
)
{
// if caller's role is Broadcaster, SupMod, BotAdmin , they can Promote target Chatters to become Mod (i.e., the target user is not a Mod,SupMod,BotAdmin)
botinstance::botlog::trace(&format!("Attempting promote..."),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
let ta = idlock.promote(arg1.to_string().to_lowercase(),
Some(ChType::Channel(msg.channel_login.to_lowercase())),
2024-02-14 01:09:55 -05:00
Some(UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase())))).await;
2024-02-25 10:40:54 -05:00
match ta {
ChangeResult::Success(a) => {
// println!("Succesfully promoted : {a} ;");
let outmsg = &format!("Successful Promotion : {a}");
botinstance::botlog::debug(&format!("Successful Promotion : {a}"),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// let outmsg = "o7 Successfully promoted : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
ChangeResult::Failed(a) => {
// println!("Failed to promote : {a} ; ");
let outmsg = &format!("PoroSad failed to promote : {a}");
botinstance::botlog::debug(outmsg,
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
// Log::flush();
// let outmsg = "PoroSad failed to promote : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
ChangeResult::NoChange(a) => {
// println!("No Changes Made : {a} ; ");
let outmsg = &format!("uuh Not making any changes : {a}");
botinstance::botlog::debug(outmsg,
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// let outmsg = "uuh No Promotion Change : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
}
} else if trgusrroles.contains(&UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase()))) &&
( senderroles.contains(&UserRole::Broadcaster) ||
senderroles.contains(&UserRole::BotAdmin) )
{
botinstance::botlog::trace(&format!("Attempting promote..."),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// broadcaster & botadmins can make mods into SupMod
let ta = idlock.promote(arg1.to_string().to_lowercase(),
Some(ChType::Channel(msg.channel_login.to_lowercase())),
Some(UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase())))).await;
match ta {
ChangeResult::Success(a) => {
// println!("Succesfully promoted : {a} ;");
let outmsg = &format!("Successful Promotion : {a}");
botinstance::botlog::debug(&format!("Successful Promotion : {a}"),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// let outmsg = "o7 Successfully promoted : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
ChangeResult::Failed(a) => {
// println!("Failed to promote : {a} ; ");
let outmsg = &format!("PoroSad failed to promote : {a}");
botinstance::botlog::debug(outmsg,
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
// Log::flush();
// let outmsg = "PoroSad failed to promote : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
ChangeResult::NoChange(a) => {
// println!("No Changes Made : {a} ; ");
let outmsg = &format!("uuh No Change in Promotion : {a}");
botinstance::botlog::debug(outmsg,
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// let outmsg = "uuh No Promotion Change : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
}
} else if trgusrroles.contains(&UserRole::Broadcaster) // This should always be NoChange
{
botinstance::botlog::trace(&format!("Attempting promote..."),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// broadcaster & botadmins can make mods into superadmins
let ta = idlock.promote(arg1.to_string().to_lowercase(),
Some(ChType::Channel(msg.channel_login.to_lowercase())),
Some(UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase())))).await;
match ta {
ChangeResult::Success(a) => {
// println!("Succesfully promoted : {a} ;");
let outmsg = &format!("Successful Promotion : {a}");
botinstance::botlog::debug(&format!("Successful Promotion : {a}"),
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// let outmsg = "o7 Successfully promoted : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
ChangeResult::Failed(a) => {
// println!("Failed to promote : {a} ; ");
let outmsg = &format!("PoroSad failed to promote : {a}");
botinstance::botlog::debug(outmsg,
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
// Log::flush();
// let outmsg = "PoroSad failed to promote : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
ChangeResult::NoChange(a) => {
// println!("No Changes Made : {a} ; ");
let outmsg = &format!("uuh No Change in Promotion : {a}");
botinstance::botlog::debug(outmsg,
Some("identity.rs > cmd_prommote()".to_string()), Some(&msg));
Log::flush();
// let outmsg = "uuh No Promotion Change : ".to_string();
bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await;
},
}
}
else {
let s = botlog::fatal("Reached unreachable else",
Some("identity > cmd_promote()".to_string()), Some(&msg));
panic!("{}",s);
};
Log::flush();
}
_ => (),
}
2024-02-14 01:09:55 -05:00
2024-02-13 19:49:36 -05:00
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
let arg2 = argv.next();
2024-02-14 01:09:55 -05:00
2024-02-25 10:40:54 -05:00
let targetchnl = arg2;
2024-02-14 01:09:55 -05:00
2024-02-25 10:40:54 -05:00
*/
2024-02-14 01:09:55 -05:00
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
&format!("End of cmd_promote()"),
Some("identity.rs > cmd_prommote()".to_string()),
None,
);
2024-01-29 11:09:33 -05:00
}
2024-02-12 02:34:32 -05:00
// 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 {
2024-02-25 10:40:54 -05:00
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,
2024-02-25 10:40:54 -05:00
],
2024-02-12 02:34:32 -05:00
};
2024-02-25 10:40:54 -05:00
2024-02-12 02:34:32 -05:00
tempb.add_to_modmgr(Arc::clone(&mgr)).await;
2024-01-29 11:09:33 -05:00
2024-02-12 01:25:12 -05:00
// async fn cmd_demote(mut _chat:Arc<Mutex<BotInstance>>,_msg:PrivmsgMessage) {
2024-02-25 10:40:54 -05:00
async fn cmd_demote(mut bot: BotAR, msg: PrivmsgMessage) {
2024-02-13 10:11:49 -05:00
// println!("Called cmd demote");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
"Called cmd demote",
Some("identity.rs > cmd_demote()".to_string()),
Some(&msg),
);
2024-02-14 01:09:55 -05:00
Log::flush();
2024-02-25 10:40:54 -05:00
2024-02-14 01:09:55 -05:00
// -- 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
2024-02-25 10:40:54 -05:00
- [ ] `UserRole`s that can run, can
2024-02-14 01:09:55 -05:00
- [ ] run `promote` on a regular `Chatter` to make them a `Mod`
- [ ] run `demote` on a `Mod` to make them a `Chatter`
2024-02-25 10:40:54 -05:00
- [ ] Only `BotAdmin` can :
2024-02-14 01:09:55 -05:00
- [ ] target themselves to `promote` / `demote` , in the case that they want to make themselves either a `Mod` or `SupMod` for the channel temporarily
2024-02-25 10:40:54 -05:00
- [ ] `promote admin <Chatter>` to assign them `BotAdmin` role
2024-02-14 01:09:55 -05:00
- `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` or `promote` the other way
*/
2024-01-29 11:09:33 -05:00
2024-02-14 01:09:55 -05:00
/*
2024-02-25 10:40:54 -05:00
Usage :
2024-02-14 01:09:55 -05:00
promote <user>
2024-02-25 10:40:54 -05:00
demote <user>
2024-02-14 01:09:55 -05:00
promote -admin <user>
2024-02-25 10:40:54 -05:00
2024-02-14 01:09:55 -05:00
*/
2024-01-31 21:30:08 -05:00
// [ ] #TODO : Need to define the body that calls demote()
// [x] Unwraps arguments from message
// let mut argv = msg.message_text.split(" ");
2024-02-25 10:40:54 -05:00
// argv.next(); // Skip the command name
// let arg1 = argv.next();
// let arg2 = argv.next();
2024-02-25 10:40:54 -05:00
let (arg1, arg2) = {
let mut argv = msg.message_text.split(" ");
2024-02-25 10:40:54 -05:00
argv.next(); // Skip the command name
2024-02-25 10:40:54 -05:00
let arg1 = argv.next();
let arg2 = argv.next();
2024-02-25 10:40:54 -05:00
(arg1, arg2)
};
/*
let mut sender_badge:Option<ChatBadge> = 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);
}
}
*/
// ---
/*
2024-02-25 10:40:54 -05:00
=> 2024.02.15 - The business logic seems embeded straight into demote() with the following in mind :
- demote() atm doesn't take sender ChatBadge <-- the assumption is canuserrun() was done
for this user, and automatically assigned any roles that should get auto assigned
- demote() returns a ChangeResult
2024-02-25 10:40:54 -05:00
- [ ] So I think all I need to do here is parse out and pass input args to demote(), and output quirky messages based on ChangeResult
- [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
- [ ] 3. Take ChangeResult and output response
2024-02-25 10:40:54 -05:00
*/
/*
2024-02-25 10:40:54 -05:00
- [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)
2024-02-25 10:40:54 -05:00
*/
let sendername = msg.clone().sender.name;
2024-02-25 10:40:54 -05:00
let mut sender_badge_mut: Option<ChatBadge> = None;
for b in &msg.badges {
if b.name == "moderator" {
sender_badge_mut = Some(ChatBadge::Mod);
} else if b.name == "broadcaster" {
sender_badge_mut = Some(ChatBadge::Broadcaster);
}
}
let sender_badge = sender_badge_mut;
let targetusr = arg1;
let targetchnl = msg.channel_login.to_lowercase();
/*
2024-02-25 10:40:54 -05:00
- [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
2024-02-25 10:40:54 -05:00
*/
2024-02-25 10:40:54 -05:00
// [x] Get a required lock first
2024-02-25 10:40:54 -05:00
let botlock = bot.read().await;
let id = botlock.get_identity();
let idlock = id.read().await;
let rslt = match targetusr {
Some(targetusr) => {
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("running demote()"),
Some("identity.rs > cmd_demote()".to_string()),
None,
);
Log::flush();
2024-02-25 10:40:54 -05:00
idlock
.demote(
sendername.clone(),
&sender_badge,
targetusr.to_string(),
Some(ChType::Channel(targetchnl.clone())),
)
.await
}
None => {
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("No Targer User argument"),
Some("identity.rs > cmd_demote()".to_string()),
None,
);
Log::flush();
ChangeResult::NoChange("No Targer User".to_string())
}
};
/*
2024-02-25 10:40:54 -05:00
- [x] 3. Take ChangeResult and output response
2024-02-25 10:40:54 -05:00
*/
// let senderUserRole = {
2024-02-25 10:40:54 -05:00
// // note : getspecialuserroles will cover :
// // - Internal roles stored at db for Mod & SupMod & BotAdmin
// // - Broadcaster (based on target hchatter & channel)
// // It MAY NOT COVER sutations where Sender has a Mod Badge, but not in DB yet as Mod
// // - So ideally this covers that (at least returns that they're a mod and go ahead and run for now)
// // - [ ] #TODO : This should also go ahead and add that mod to DB if possible as channel mod
// // let evalroles = vec![];
// let evalroles = match sender_badge {
// Some(ChatBadge::Mod) => {
// let mut rslroles = idlock.getspecialuserroles(
2024-02-25 10:40:54 -05:00
// sendername.clone(),
// Some(ChType::Channel(targetchnl.clone()))).await;
// rslroles.push(UserRole::Mod(ChType::Channel(targetchnl)));
// rslroles
// },
// _ => {
// idlock.getspecialuserroles(
2024-02-25 10:40:54 -05:00
// sendername,
// Some(ChType::Channel(targetchnl.clone()))).await
// }
// };
2024-02-25 10:40:54 -05:00
// // => 02.16 - I think better would just migrate over the logic within demote
// // - If there's business reqs to evaluate , better to keep the ChangeResult
// // consistent and also pass ChatBadge
// }; // senderUserRole
match rslt {
ChangeResult::Success(a) => {
// println!("Succesfully promoted : {a} ;");
let outmsg = &format!("o7 Successfully demoted : {a}");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
outmsg,
Some("identity.rs > cmd_demote()".to_string()),
Some(&msg),
);
// let outmsg = "o7 Successfully promoted : ".to_string();
2024-02-25 10:40:54 -05:00
botlock
.botmgrs
.chat
.say_in_reply_to(&msg, outmsg.to_string())
.await;
}
ChangeResult::Failed(a) => {
// println!("Failed to promote : {a} ; ");
let outmsg = &format!("PoroSad failed to demote : {a}");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
outmsg,
Some("identity.rs > cmd_demote()".to_string()),
Some(&msg),
);
// let outmsg = "PoroSad failed to promote : ".to_string();
2024-02-25 10:40:54 -05:00
botlock
.botmgrs
.chat
.say_in_reply_to(&msg, outmsg.to_string())
.await;
}
ChangeResult::NoChange(a) => {
// println!("No Changes Made : {a} ; ");
let outmsg = &format!("uuh No Demotion Change : {a}");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
outmsg,
Some("identity.rs > cmd_demote()".to_string()),
Some(&msg),
);
// let outmsg = "uuh No Promotion Change : ".to_string();
2024-02-25 10:40:54 -05:00
botlock
.botmgrs
.chat
.say_in_reply_to(&msg, outmsg.to_string())
.await;
}
}
// println!("tester");
// println!("tester2");
2024-02-14 09:21:50 -05:00
}
2024-02-25 10:40:54 -05:00
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![
2024-01-31 21:30:08 -05:00
UserRole::Mod(ChType::Channel(String::new())),
UserRole::SupMod(ChType::Channel(String::new())),
UserRole::Broadcaster,
UserRole::BotAdmin,
2024-02-25 10:40:54 -05:00
],
2024-02-12 02:34:32 -05:00
};
2024-01-31 21:30:08 -05:00
2024-02-25 10:40:54 -05:00
tempcomm.add_to_modmgr(Arc::clone(&mgr)).await;
2024-01-31 21:30:08 -05:00
2024-02-12 01:25:12 -05:00
// async fn getroles(bot:Arc<Mutex<BotInstance>>,msg:PrivmsgMessage) {
2024-02-25 10:40:54 -05:00
async fn getroles(bot: BotAR, msg: PrivmsgMessage) {
2024-02-13 10:11:49 -05:00
// println!("Called cmd getroles");
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
"Called cmd getroles",
Some("identity.rs > cmd_getroles()".to_string()),
Some(&msg),
);
2024-01-31 21:30:08 -05:00
/*
Usage
getroles <user> <Channel>
2024-02-25 10:40:54 -05:00
- If channel is provided, provide roles for that channel specifically
2024-01-31 21:30:08 -05:00
*/
2024-02-25 10:40:54 -05:00
// IN other code areas , I see this
2024-01-31 21:30:08 -05:00
// ServerMessage::Privmsg(msg) => {
// println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
2024-02-01 08:40:09 -05:00
// println!("{}",msg.message_text);
2024-01-31 21:30:08 -05:00
let mut argv = msg.message_text.split(" ");
// for v in argv {
// println!("args : {v}");
// }
2024-02-01 08:40:09 -05:00
argv.next(); // Skip the command name
2024-01-31 21:30:08 -05:00
let arg1 = argv.next();
// if arg == None {
// return ; // Do nothing if no arguments
// }
let targetuser = match arg1 {
2024-02-25 10:40:54 -05:00
None => return, // exit if no arguments
2024-01-31 21:30:08 -05:00
Some(arg) => arg,
};
// match String::from(arg1) {
// a if a == String::from("admin") => (),
// _ => (),
// }
// match argv[1] {
// String::from("admin") => (),
// }
let arg2 = argv.next();
2024-02-25 10:40:54 -05:00
let targetchnl = arg2;
2024-01-31 21:30:08 -05:00
2024-02-04 14:28:37 -05:00
// // 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();
2024-02-12 01:25:12 -05:00
// let a = bot.clone();
2024-02-04 14:28:37 -05:00
// let a = a.lock().await;
2024-02-12 01:25:12 -05:00
// let a = a.get_identity();
// let a = a.lock().await;
// let a = bot.get_identity();
let botlock = bot.read().await;
2024-02-13 10:11:49 -05:00
// println!("botlock read");
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
"botlock read",
Some("identity.rs > init > getroles()".to_string()),
Some(&msg),
);
2024-02-12 01:25:12 -05:00
let idlock = botlock.get_identity();
2024-02-13 10:11:49 -05:00
// println!("got identity");
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
"got identity",
Some("identity.rs > init > getroles()".to_string()),
Some(&msg),
);
2024-02-12 05:25:38 -05:00
let idlock = idlock.read().await; // <-- 02.12 - Latest where it gest stuck - before or at this point
2024-02-25 10:40:54 -05:00
// println!("id lock");
botinstance::botlog::trace(
"id lock",
Some("identity.rs > init > getroles()".to_string()),
Some(&msg),
);
2024-02-04 14:28:37 -05:00
let sproles = match targetchnl {
2024-01-31 21:30:08 -05:00
None => {
2024-02-04 14:28:37 -05:00
// 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);
2024-02-12 01:25:12 -05:00
// let a = idlock.read().await;
2024-02-13 19:49:36 -05:00
// idlock.getspecialuserroles(String::from(targetuser),None).await
// [ ] If targetchnl is not provided, default to pulling the current channel
2024-02-25 10:40:54 -05:00
idlock
.getspecialuserroles(
String::from(targetuser),
Some(ChType::Channel(msg.channel_login.to_lowercase())),
)
.await
}
2024-01-31 21:30:08 -05:00
Some(targetchnl) => {
2024-02-04 14:28:37 -05:00
// 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)
2024-02-12 01:25:12 -05:00
// let a = a.read().await;
2024-02-13 19:49:36 -05:00
// [ ] 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<ChatBadge> = 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) => {
// }
// _ => {
2024-02-25 10:40:54 -05:00
2024-02-13 19:49:36 -05:00
// }
2024-02-25 10:40:54 -05:00
// }
2024-02-13 19:49:36 -05:00
// [x]gets special roles for caller
2024-02-25 10:40:54 -05:00
let callersproles = idlock
.getspecialuserroles(
msg.sender.name.to_lowercase(),
Some(ChType::Channel(targetchnl.to_lowercase().to_string())),
)
.await;
2024-02-13 19:49:36 -05:00
// 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())));
2024-02-25 10:40:54 -05:00
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
2024-02-13 19:49:36 -05:00
// callersproles
} else {
// Otherwise, don't get the target channel, return the current channel instead
2024-02-25 10:40:54 -05:00
idlock
.getspecialuserroles(
String::from(targetuser),
Some(ChType::Channel(msg.channel_login.to_lowercase())),
)
.await
2024-02-13 19:49:36 -05:00
}
2024-02-25 10:40:54 -05:00
}
2024-02-04 14:28:37 -05:00
};
2024-01-31 21:30:08 -05:00
2024-02-13 19:49:36 -05:00
// let sproles = idlock.getspecialuserroles(String::from(targetuser),).await;
2024-02-13 10:11:49 -05:00
// println!("Retrieved User Roles >> {:?}",sproles);
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("User roles of Target Chatter >> {:?}", sproles),
Some("identity.rs > init > getroles()".to_string()),
Some(&msg),
);
2024-02-13 19:49:36 -05:00
// # I believe at this stage I still have botlock active
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("Evaluating special roles"),
Some("identity.rs > init > getroles()".to_string()),
Some(&msg),
);
2024-02-13 19:49:36 -05:00
// let mut outmsg = String::new();
let sproles = sproles;
// let arg2 = arg2.unwrap();
2024-01-31 21:30:08 -05:00
2024-02-25 10:40:54 -05:00
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
let mut outmsg = format!("FeelsWowMan they're the broadcaster. ");
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)
{
outmsg = outmsg + &format!("Target chatter's user roles are : {:?}", sproles);
2024-02-13 19:49:36 -05:00
}
2024-02-25 10:40:54 -05:00
outmsg
} 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 ")
};
2024-02-13 19:49:36 -05:00
2024-02-25 10:40:54 -05:00
// if sproles.contains(&UserRole::Mod(msg.channel_login.to_lowercase())) {
2024-02-13 19:49:36 -05:00
2024-02-25 10:40:54 -05:00
// } else if sproles.contains(&UserRole::Mod(msg.channel_login.to_lowercase())) {
2024-02-13 19:49:36 -05:00
2024-02-25 10:40:54 -05:00
// }
2024-02-13 19:49:36 -05:00
2024-02-25 10:40:54 -05:00
// let outmsg = match sproles
2024-02-13 19:49:36 -05:00
// {
// // let mut outmsg = String::new();
// Some(sproles) => {
// let sproles = sproles.read().await;
// format!("Target chatter's user roles are : {:?}",sproles)
2024-02-25 10:40:54 -05:00
// }
2024-02-13 19:49:36 -05:00
// 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());
2024-02-25 10:40:54 -05:00
// botinstance::botlog::debug(&format!("Evaluating special roles > channel login : {} ; message text : {} ; ",&msg.channel_login,&msg.message_text),
2024-02-13 19:49:36 -05:00
// Some("identity.rs > init > getroles()".to_string()), Some(&msg));
// botinstance::botlog::debug(&format!("Evaluating special roles > bool evaluation : {} ",
2024-02-25 10:40:54 -05:00
// msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase())),
2024-02-13 19:49:36 -05:00
// 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 ")
// }
// }
2024-02-25 10:40:54 -05:00
2024-02-13 19:49:36 -05:00
// };
2024-01-31 21:30:08 -05:00
// let a = bot.identity.getuserroles(String::from("ModulatingForce"), Some(ChType::Channel(String::from("ModulatingForcebot"))));
// println!("{:?}",a);
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("Chat Say Reply message : {:?}", outmsg),
Some("identity.rs > init > getroles()".to_string()),
Some(&msg),
);
2024-02-13 19:49:36 -05:00
botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await;
2024-02-25 10:40:54 -05:00
// [ ] 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
2024-01-31 21:30:08 -05:00
}
2024-02-13 10:11:49 -05:00
// println!("End of Init MOdule add");
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
"End of Init MOdule add",
Some("identity.rs > init ".to_string()),
None,
);
2024-01-31 21:30:08 -05:00
2024-02-13 19:49:36 -05:00
Log::flush();
2024-01-29 11:09:33 -05:00
}
2024-01-29 22:57:07 -05:00
// #[derive(Debug, PartialEq, Eq, Hash, Clone)]
// pub enum ChType {
// Channel(String),
// }
2024-02-25 10:40:54 -05:00
#[derive(Debug, PartialEq, Eq, Clone)]
2024-01-29 11:09:33 -05:00
pub enum UserRole {
2024-02-25 10:40:54 -05:00
Chatter,
Mod(ChType), // String specifies Channel
SupMod(ChType), // String specifies Channel
Broadcaster,
BotAdmin,
2024-01-29 06:18:27 -05:00
}
2024-01-29 22:57:07 -05:00
pub enum Permissible {
2024-02-25 10:40:54 -05:00
Allow,
Block,
2024-01-29 12:41:26 -05:00
}
2024-01-31 18:36:23 -05:00
#[derive(Clone)]
2024-01-29 06:18:27 -05:00
pub struct IdentityManager {
2024-02-04 14:28:37 -05:00
// special_roles_users : HashMap<String,Vec<UserRole>>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel
2024-02-12 05:25:38 -05:00
// special_roles_users : Arc<Mutex<HashMap<String,Vec<UserRole>>>>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel
2024-02-25 10:40:54 -05:00
// special_roles_users : Arc<RwLock<HashMap<String,Vec<UserRole>>>>,
special_roles_users: Arc<RwLock<HashMap<String, Arc<RwLock<Vec<UserRole>>>>>>,
2024-01-31 09:31:14 -05:00
// parent_mgr : Box<crate::core::botinstance::BotManagers>,
2024-01-31 21:30:08 -05:00
//parent_mgr : Option<Box<crate::core::botinstance::BotManagers>>,
2024-02-25 10:40:54 -05:00
}
/*
HashMap<
String, <-- Chatter / Username
Vec<UserRole> -- <-- Vectors are basically arrays
>
2024-02-25 10:40:54 -05:00
-- [ ]
let a = vec![]
modulatingforce : vec![UserRole::BotAdmin,
UserRole::Mod(ChType::Channel("modulatingforcebot"))]
modulatingforce : vec![UserRole::BotAdmin,
UserRole::Mod(ChType::Channel("modulatingforcebot"))]
*/
2024-01-29 06:18:27 -05:00
#[derive(Debug)]
2024-01-29 22:57:07 -05:00
pub enum ChatBadge {
2024-01-29 12:41:26 -05:00
Broadcaster,
Mod,
}
2024-02-25 10:40:54 -05:00
#[derive(Debug, PartialEq, Eq)]
2024-02-13 07:54:35 -05:00
pub enum ChangeResult {
2024-01-31 21:30:08 -05:00
Success(String),
Failed(String),
NoChange(String),
}
2024-01-29 06:18:27 -05:00
impl IdentityManager {
pub fn init() -> IdentityManager {
let mut a = HashMap::new();
for admn in adminvector() {
2024-02-25 10:40:54 -05:00
a.insert(
admn.to_lowercase(),
Arc::new(RwLock::new(vec![UserRole::BotAdmin])),
);
}
2024-01-29 06:18:27 -05:00
IdentityManager {
2024-02-25 10:40:54 -05:00
special_roles_users: Arc::new(RwLock::new(a)),
2024-01-31 21:30:08 -05:00
//parent_mgr : None,
2024-01-29 06:18:27 -05:00
}
}
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
async fn add_role(&self, trgchatter: String, trg_role: UserRole) {
2024-02-18 19:23:50 -05:00
let mut srulock = self.special_roles_users.write().await;
let mut usrrolelock = srulock
.get_mut(&trgchatter)
.expect("Error retrieving roles")
2024-02-25 10:40:54 -05:00
.write()
.await;
usrrolelock.push(trg_role);
2024-02-18 19:23:50 -05:00
}
2024-02-25 10:40:54 -05:00
async fn remove_role(&self, trgchatter: String, trg_role: UserRole) {
2024-02-18 19:23:50 -05:00
let mut srulock = self.special_roles_users.write().await;
let mut usrrolelock = srulock
.get_mut(&trgchatter)
.expect("Error retrieving roles")
2024-02-25 10:40:54 -05:00
.write()
.await;
if let Some(indx) = usrrolelock.iter().position(|value| *value == trg_role) {
2024-02-18 19:23:50 -05:00
usrrolelock.swap_remove(indx);
//return ChangeResult::Success("Demoted successfully".to_string())
}
}
2024-02-25 10:40:54 -05:00
async fn affirm_chatter_in_db(&self, trgchatter: String) {
2024-02-18 19:23:50 -05:00
let mut srulock = self.special_roles_users.write().await;
2024-02-25 10:40:54 -05:00
srulock
.entry(trgchatter.clone())
.or_insert(Arc::new(RwLock::new(vec![])));
botinstance::botlog::trace(
&format!(
"Ensuring User in Roles {:?}",
srulock.entry(trgchatter.clone())
),
Some("IdentityManager > affirm_chatter_in_db()".to_string()),
None,
);
2024-02-18 19:23:50 -05:00
Log::flush();
}
2024-01-29 22:57:07 -05:00
// [ ] Maybe I should create a can_user_run version that simply takes PrvMsg, but then calls can_user_run directly
2024-02-25 10:40:54 -05:00
// pub fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec<UserRole>) -> Result<Permissible,Box<dyn Error>>
2024-02-04 14:28:37 -05:00
// pub fn can_user_run_PRVMSG(&self,msg:&PrivmsgMessage,cmdreqroles:Vec<UserRole>) -> Permissible
2024-02-25 10:40:54 -05:00
// pub async fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec<UserRole>) -> Permissible
pub async fn can_user_run_PRVMSG(
&mut self,
msg: &PrivmsgMessage,
cmdreqroles: Vec<UserRole>,
) -> (Permissible, ChangeResult) {
2024-01-29 22:57:07 -05:00
// println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
// [ ] Check what Badges in PrivmsgMessage
2024-02-13 10:11:49 -05:00
// println!{"Checking within PRVMSG"};
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
"Checking within PRVMSG",
Some("identity.rs > can_user_run_PRVMSG()".to_string()),
Some(&msg),
);
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
let mut sender_badge: Option<ChatBadge> = None;
2024-01-29 22:57:07 -05:00
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{}) {
// }
2024-02-13 19:49:36 -05:00
// if let Some(sender_badge) = sender_badge {
// match sender_badge {
// Some(sender_badge) => {
2024-02-25 10:40:54 -05:00
// 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 => {
// }
2024-02-13 19:49:36 -05:00
// here , sender_badge is likely None
// This could be a regular chatter, BotAdmin,SupserMod
2024-01-29 22:57:07 -05:00
// [ ] Call can_user_run()
2024-02-12 01:25:12 -05:00
// (self,Permissible::Block)
2024-02-13 19:49:36 -05:00
// (Permissible::Block,ChangeResult::NoChange("".to_string()))
2024-02-25 10:40:54 -05:00
self.can_user_run(
msg.sender.name.to_owned(),
ChType::Channel(msg.channel_login.to_owned()),
sender_badge,
cmdreqroles,
)
.await
2024-01-29 22:57:07 -05:00
}
2024-02-25 10:40:54 -05:00
pub async fn can_user_run(
&mut self,
usr: String,
channelname: ChType,
chat_badge: Option<ChatBadge>,
cmdreqroles: Vec<UserRole>, // ) -> Result<Permissible,Box<dyn Error>> {
) -> (Permissible, ChangeResult) {
// println!{"Checking within can_user_run()"};
botinstance::botlog::debug(
&format!(
"Checking within can_user_run() :
usr : {} ; channel : {:?} ; badge : {:?} ; cmdreqroles : {:?}",
2024-02-25 10:40:54 -05:00
usr, channelname, chat_badge, cmdreqroles
),
Some("identity.rs > can_user_run()".to_string()),
None,
);
/*
canUserRun -
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
Input :
usr:String,
channelname:ChType,
chat_badge:ChatBadge,
cmdreqroles:Vec<UserRole>
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
Output : Result<Permissible,Box<dyn Error>>
Some Possible outcomes : Ok(Permissible::Allow) , Ok(Permissible::Block)
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
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
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
Inputs and business logic determine if the user can run the command based on the command's required roles
*/
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
// 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)
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
// let idar = Arc::new(RwLock::new(self));
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
let usr = usr.to_lowercase();
2024-01-29 12:41:26 -05:00
2024-02-25 10:40:54 -05:00
if cmdreqroles.len() == 0 {
// return Ok(Permissible::Allow)
return (
Permissible::Allow,
ChangeResult::NoChange("Command has no required cmdreqroles".to_string()),
);
}
2024-02-12 05:25:38 -05:00
2024-02-25 10:40:54 -05:00
let mut modrolechange = ChangeResult::NoChange("".to_string());
2024-02-25 10:40:54 -05:00
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())))
{
2024-01-29 22:57:07 -05:00
// return Ok(Permissible::Allow)
2024-02-25 10:40:54 -05:00
return (
Permissible::Allow,
ChangeResult::NoChange("Broadcaster Role".to_string()),
);
2024-01-29 22:57:07 -05:00
}
2024-02-25 10:40:54 -05:00
}
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// [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 arc 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,
);
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// {
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// // If target user doesn't exist in special_roles_users , add with blank vector roles
// let mut srulock = self.special_roles_users.write().await;
// srulock.entry(usr.clone()).or_insert(Arc::new(RwLock::new(vec![])));
// botinstance::botlog::trace(&format!("Ensuring Chatter in Roles {:?}",srulock.entry(usr.clone())),
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
self.affirm_chatter_in_db(usr.clone()).await;
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
2024-01-29 22:57:07 -05:00
}
2024-02-25 10:40:54 -05:00
}
_ => (), // Don't handle other roles here
}
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// [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)
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// println!("cmd required roles : {:?}",cmdreqroles);
botinstance::botlog::trace(
&format!("cmd required roles : {:?}", cmdreqroles),
Some("identity.rs > can_user_run()".to_string()),
None,
);
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
if cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) {
// match self.special_roles_users.get(&channelname) {
// Some(usrroles) => {},
// None => (),
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// }
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// 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);
2024-01-29 22:57:07 -05:00
}
2024-02-25 10:40:54 -05:00
}
}
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
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);
2024-01-29 22:57:07 -05:00
}
2024-02-25 10:40:54 -05:00
}
}
2024-01-29 22:57:07 -05:00
2024-02-25 10:40:54 -05:00
// [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);
2024-01-29 22:57:07 -05:00
}
2024-02-25 10:40:54 -05:00
}
2024-01-29 12:41:26 -05:00
}
2024-01-31 21:30:08 -05:00
2024-02-25 10:40:54 -05:00
(
Permissible::Block,
ChangeResult::NoChange("Not any permissiable condition".to_string()),
)
}
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
// pub async fn promote(&mut self,trgchatter:String,channel:Option<ChType>,trg_role:Option<UserRole>) -> ChangeResult {
pub async fn promote(
&self,
authorizer: String,
authorizer_badge: &Option<ChatBadge>,
trgchatter: String,
channel: Option<ChType>,
trg_role: Option<UserRole>,
) -> ChangeResult {
botinstance::botlog::trace(
&format!(
"IN VARS for promote() : auth : {} ; authbadge : {:?} ; trg : {} ; Channel {:?} ; {:?}",
2024-02-25 10:40:54 -05:00
authorizer,authorizer_badge,trgchatter,channel,trg_role),
Some("identity.rs > promote()".to_string()),
None,
);
2024-02-14 01:09:55 -05:00
Log::flush();
2024-02-01 08:40:09 -05:00
/*
[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
- 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
- NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod
2024-02-25 10:40:54 -05:00
*/
// [x] 1. Check if Authorizer Mod Badge then Auto Promote to Mod if not Mod
2024-02-18 16:01:28 -05:00
let trgchatter = trgchatter.to_lowercase();
2024-02-25 10:40:54 -05:00
let (authusrroles, trgusrroles) = if let Some(channel) = channel.clone() {
let mut authusrroles = self
.getspecialuserroles(authorizer.to_lowercase().clone(), Some(channel.clone()))
.await;
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
{
// mut block
// let authusrroles_mut = &mut authusrroles;
// [x] Add Mod(channel) to authusrroles
// [x] #TODO also add to DB if possible?
match *authorizer_badge {
2024-02-25 10:40:54 -05:00
Some(ChatBadge::Mod)
if (!authusrroles.contains(&UserRole::Mod(channel.clone()))
&& !authusrroles.contains(&UserRole::SupMod(channel.clone()))) =>
{
// (*authusrroles_mut).push(UserRole::Mod(channel.clone()));
authusrroles.push(UserRole::Mod(channel.clone()));
2024-02-18 19:23:50 -05:00
// 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(channel.clone()));
2024-02-19 21:04:01 -05:00
self.affirm_chatter_in_db(authorizer.clone()).await;
2024-02-25 10:40:54 -05:00
self.add_role(authorizer.clone(), UserRole::Mod(channel.clone()))
.await;
}
2024-02-25 10:40:54 -05:00
_ => (),
}
} // mut block
2024-02-25 10:40:54 -05:00
// [x] 2. Get Authorizer & Target Chatter Roles
2024-02-25 10:40:54 -05:00
let trgusrroles = self
.getspecialuserroles(trgchatter.to_lowercase().clone(), Some(channel.clone()))
.await;
2024-02-25 10:40:54 -05:00
(authusrroles, trgusrroles)
} else {
let mut authusrroles = self
.getspecialuserroles(authorizer.to_lowercase().clone(), None)
.await;
let trgusrroles = self
.getspecialuserroles(trgchatter.to_lowercase().clone(), None)
.await;
(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());
}
// [x] 4a. If Authorizer is BotAdmin & trg_role is Some(BotAdmin) , set Target as BotAdmin and return
if authusrroles.contains(&UserRole::BotAdmin) && trg_role == Some(UserRole::BotAdmin) {
if trgusrroles.contains(&UserRole::BotAdmin) {
return ChangeResult::NoChange("Already has the role".to_string());
} else {
2024-02-18 19:23:50 -05:00
// {
// let mut srulock = self.special_roles_users.write().await;
2024-02-04 14:28:37 -05:00
2024-02-18 19:23:50 -05:00
// srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![])));
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Ensuring Target Chatter in Roles > {:?}",srulock.entry(trgchatter.clone())),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
self.affirm_chatter_in_db(trgchatter.clone()).await;
2024-02-18 19:23:50 -05:00
// {
2024-02-18 19:23:50 -05:00
// let mut srulock = self.special_roles_users.write().await;
2024-02-18 19:23:50 -05:00
// srulock
// .get_mut(&trgchatter)
// .expect("Error getting roles for the user")
// .write().await
// .push(UserRole::BotAdmin); // <-- Adds the specific role
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Inserting Role > {:?}",srulock.entry(trgchatter.clone())),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
self.add_role(trgchatter.clone(), UserRole::BotAdmin).await;
return ChangeResult::Success("Promotion Successful".to_string());
}
}
// [x] 4b. If target is Broadcaster, return NoChange
if trgusrroles.contains(&UserRole::Broadcaster) {
return ChangeResult::NoChange("Can't target broadcaster".to_string());
}
/*
2024-02-25 10:40:54 -05:00
[ ] 4c. 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
- NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod
*/
// let authhasnsreqroles = match channel.clone() {
2024-02-25 10:40:54 -05:00
// Some(channel) => authusrroles.contains(&UserRole::SupMod(channel.clone())) ||
// authusrroles.contains(&UserRole::BotAdmin) ||
// authusrroles.contains(&UserRole::Broadcaster) ,
// None => authusrroles.contains(&UserRole::BotAdmin),
2024-02-04 14:28:37 -05:00
// };
2024-02-01 08:40:09 -05:00
if let Some(trg_chnl) = channel.clone() {
2024-02-25 10:40:54 -05:00
if !trgusrroles.contains(&UserRole::Broadcaster)
&& !trgusrroles.contains(&UserRole::Mod(trg_chnl.clone()))
&& !trgusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
{
// target user is neither Mod nor SupMod && not broadcaster
// target's Next Role would be Mod
2024-02-25 10:40:54 -05:00
// Authorizer must be SupMod,Broadcaster,BotAdmin
// > Promote target to Mod
2024-02-25 10:40:54 -05:00
if authusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
|| authusrroles.contains(&UserRole::Broadcaster)
|| authusrroles.contains(&UserRole::BotAdmin)
{
2024-02-18 19:23:50 -05:00
// {
2024-02-18 19:23:50 -05:00
// // If target user doesn't exist in special_roles_users , add with blank vector roles
// let mut srulock = self.special_roles_users.write().await;
// srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![])));
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Ensuring Chatter in Roles {:?}",srulock.entry(trgchatter.clone())),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
self.affirm_chatter_in_db(trgchatter.clone()).await;
// {
2024-02-25 10:40:54 -05:00
// // promote target after
2024-02-18 19:23:50 -05:00
// let mut srulock = self.special_roles_users.write().await;
// srulock
// .get_mut(&trgchatter)
// .expect("Error getting roles")
// .write().await
// .push(UserRole::Mod(trg_chnl.clone())); // Role to Add
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Adding Roles to Chatter {:?}",srulock.entry(trgchatter.clone())),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
2024-02-25 10:40:54 -05:00
self.add_role(trgchatter.clone(), UserRole::Mod(trg_chnl.clone()))
.await;
2024-02-25 10:40:54 -05:00
return ChangeResult::Success(String::from("Promotion Successful"));
}
// Other else conditions would be mostly spcecial responses like ChangeResult::NoChange or ChangeResult::Fail
// related to authusrroles
else {
return ChangeResult::Failed(String::from("You're not permitted to do that"));
}
2024-02-25 10:40:54 -05:00
} else if !trgusrroles.contains(&UserRole::Broadcaster)
&& trgusrroles.contains(&UserRole::Mod(trg_chnl.clone()))
&& !trgusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
//
{
// target user is a Mod && not broadcaster
// target's Next Role would be SupMod
// [ ] #todo Check first if target have SupMod - Optional but could be done to cleanup first
2024-02-25 10:40:54 -05:00
// Authorizer must be Broadcaster,BotAdmin
// > Promote target to SupMod
2024-02-25 10:40:54 -05:00
if authusrroles.contains(&UserRole::Broadcaster)
|| authusrroles.contains(&UserRole::BotAdmin)
{
2024-02-18 19:23:50 -05:00
// { // Inserts user if doesn't exist
// let mut srulock = self.special_roles_users.write().await;
// srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![])));
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Ensuring User in Roles {:?}",srulock.entry(trgchatter.clone())),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
self.affirm_chatter_in_db(trgchatter.clone()).await;
// { // Adds the requested role for the user
// 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::SupMod(trg_chnl.clone()));
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Adding Required Role > {:?}",srulock.entry(trgchatter.clone())),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
2024-02-25 10:40:54 -05:00
self.add_role(trgchatter.clone(), UserRole::SupMod(trg_chnl.clone()))
.await;
2024-02-18 19:23:50 -05:00
// { // Removes the lower role (mod) from the user
// let mut srulock = self.special_roles_users.write().await;
// let mut uroleslock = srulock
// .get_mut(&trgchatter)
// .expect("Error getting roles")
// .write().await;
// if let Some(indx) = uroleslock.iter().position(|value| *value == UserRole::Mod(trg_chnl.clone())){
// uroleslock.swap_remove(indx);
// }
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Removing lower role > {:?}",uroleslock),
2024-02-18 19:23:50 -05:00
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
2024-02-25 10:40:54 -05:00
self.remove_role(trgchatter, UserRole::Mod(trg_chnl.clone()))
.await;
2024-02-12 05:25:38 -05:00
2024-02-25 10:40:54 -05:00
return ChangeResult::Success(String::from("Promotion Successful"));
} else {
return ChangeResult::Failed(String::from("You're not permitted to do that"));
}
2024-02-25 10:40:54 -05:00
} else if !trgusrroles.contains(&UserRole::Broadcaster)
&& trgusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
{
// target user is a SuMod && not broadcaster
// No Change
return ChangeResult::Failed(String::from("Already highest available role"));
2024-02-25 10:40:54 -05:00
} else {
// since handling for channel is already done, will be handling other trguserroles situations here
2024-02-25 10:40:54 -05:00
// other situations includes :
/*
2024-02-25 10:40:54 -05:00
[-] targetuser is broadcaster >> no need - this was done earlier in the function
[?] ?
*/
// At the moment, without any new roles, this should not be reached
botinstance::botlog::warn(
&format!("Code Warning : add handing for other trgusrroles"),
Some("identity.rs > promote()".to_string()),
None,
);
return ChangeResult::Failed(String::from("Code Warning"));
}
2024-02-25 10:40:54 -05:00
// let trghasreqroles =
// {
// // If target user doesn't exist in special_roles_users , add with blank vector roles
// let mut srulock = self.special_roles_users.write().await;
// srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![])));
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Ensuring Chatter in Roles {:?}",srulock.entry(trgchatter.clone())),
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
// {
2024-02-25 10:40:54 -05:00
// // promote target after
// 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.clone())); // Role to Add
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("Adding Roles to Chatter {:?}",srulock.entry(trgchatter.clone())),
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
// return ChangeResult::Success(String::from("Promotion Successful"));
};
// if authhasnsreqroles {
2024-02-25 10:40:54 -05:00
// {
// // If target user doesn't exist in special_roles_users , add with blank vector roles
// let mut srulock = self.special_roles_users.write().await;
// srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![])));
2024-02-25 10:40:54 -05:00
// botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())),
// Some("identity.rs > promote()".to_string()), None);
// Log::flush();
// }
// {
2024-02-25 10:40:54 -05:00
// // promote target after
// 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));
2024-02-25 10:40:54 -05:00
// 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"));
// }
// authusrroles.contains(&UserRole::Mod(()))
/*
let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await;
2024-02-25 10:40:54 -05:00
let rolemap = chatterroles;
2024-02-25 10:40:54 -05:00
2024-02-01 08:40:09 -05:00
match trg_role {
2024-02-14 01:09:55 -05:00
Some(UserRole::Mod(_)) => {
2024-02-25 10:40:54 -05:00
2024-02-13 19:49:36 -05:00
if let Some(trg_chnl) = channel.clone() {
// [ ] 1. If trg_role & trgchatter is a Mod or SupMod of the target channel, return NoChange
2024-02-13 19:49:36 -05:00
let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await;
let rolemap = chatterroles;
2024-02-12 05:25:38 -05:00
// let rolemap = rolemap.unwrap();
if rolemap.contains(&UserRole::Mod(trg_chnl.clone())) {
2024-02-01 08:40:09 -05:00
return ChangeResult::NoChange(String::from("Target User already has Target Role"));
2024-02-14 01:09:55 -05:00
} else if rolemap.contains(&UserRole::Broadcaster) {
return ChangeResult::NoChange(String::from("No need to do that for broadcaster"));
2024-02-01 08:40:09 -05:00
}
2024-02-14 01:09:55 -05:00
2024-02-01 08:40:09 -05:00
// # otherwise, trg_role for the given chnl is not assigned to the trgchatter
// chatterroles.push(UserRole::Mod(trg_chnl.clone()));
2024-02-13 19:49:36 -05:00
// let a = self.special_roles_users;
// let b = a.write().await;
// // let c = b.get_mut(&trgchatter);
// let c = (*b).;
// [ ] 2. Ensure an entry in Special_Roles_user for trgchatter, and push Mod(Channel) for the Target User
2024-02-13 19:49:36 -05:00
// [x] (!!) AROUND HERE - check if the user exists first, and at least add the user as we're promoting anyway
{
// If target user doesn't exist in special_roles_users , add with blank vector roles
2024-02-13 19:49:36 -05:00
let mut srulock = self.special_roles_users.write().await;
srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![])));
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())),
2024-02-13 19:49:36 -05:00
Some("identity.rs > promote()".to_string()), None);
Log::flush();
}
{
2024-02-25 10:40:54 -05:00
// promote target after
2024-02-13 19:49:36 -05:00
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));
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",srulock.entry(trgchatter.clone())),
2024-02-13 19:49:36 -05:00
Some("identity.rs > promote()".to_string()), None);
Log::flush();
}
2024-02-01 08:40:09 -05:00
return ChangeResult::Success(String::from("Promotion Successful"));
2024-02-25 10:40:54 -05:00
}
2024-02-01 08:40:09 -05:00
},
2024-02-25 10:40:54 -05:00
Some(UserRole::SupMod(_)) =>
2024-02-14 01:09:55 -05:00
{
if let Some(trg_chnl) = channel.clone() {
// [ ] 1. If trg_role & trgchatter is a Mod or SupMod of the target channel, return NoChange
2024-02-14 01:09:55 -05:00
let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await;
let rolemap = chatterroles;
// let rolemap = rolemap.unwrap();
if rolemap.contains(&UserRole::SupMod(trg_chnl.clone())) {
return ChangeResult::NoChange(String::from("Target User already has Target Role"));
} else if rolemap.contains(&UserRole::Broadcaster) {
return ChangeResult::NoChange(String::from("No need to do that for broadcaster"));
}
// # 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).;
2024-02-25 10:40:54 -05:00
// [ ] 2. Ensure an entry in Special_Roles_user for trgchatter, and push SupMod(Channel) for the Target User
2024-02-14 01:09:55 -05:00
// [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![])));
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())),
2024-02-14 01:09:55 -05:00
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::SupMod(trg_chnl.clone()));
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",srulock.entry(trgchatter.clone())),
2024-02-14 01:09:55 -05:00
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
// .(UserRole::Mod(trg_chnl));
// let indx = srulock.iter().position()
let mut uroleslock = srulock
.get_mut(&trgchatter)
.expect("Error getting roles")
// !! [ ] Unsure what happens if promoting a chatter that doesn't exist at
.write().await;
if let Some(indx) = uroleslock.iter().position(|value| *value == UserRole::Mod(trg_chnl.clone())){
uroleslock.swap_remove(indx);
}
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",uroleslock),
2024-02-14 01:09:55 -05:00
Some("identity.rs > promote()".to_string()), None);
Log::flush();
}
return ChangeResult::Success(String::from("Promotion Successful"));
}
} ,
2024-02-13 19:49:36 -05:00
Some(UserRole::BotAdmin) => {
2024-02-25 10:40:54 -05:00
2024-02-13 19:49:36 -05:00
let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await;
let rolemap = chatterroles;
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("Target Role : BotAdmin"),
2024-02-13 19:49:36 -05:00
Some("identity.rs > promote()".to_string()), None);
// [x] 1. Check their roles first if they already have botadmin
2024-02-25 10:40:54 -05:00
// [x] 2. Know that prior to promote() , BotAdmins should have been validated before being able to pass the BotAdmin target
2024-02-13 19:49:36 -05:00
// [x] 1. Check target chatter's roles first if they already have botadmin
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("Eval rolemap.contains(BotAdmin) : {}",rolemap.contains(&UserRole::BotAdmin)),
2024-02-13 19:49:36 -05:00
Some("identity.rs > promote()".to_string()), None);
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("Eval rolemap.contains(BotAdmin) > Rolemap : {:?}",rolemap),
2024-02-13 19:49:36 -05:00
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()));
2024-02-25 10:40:54 -05:00
2024-02-13 19:49:36 -05:00
// [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![])));
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())),
2024-02-13 19:49:36 -05:00
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);
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("SRLOCK - 2nd write > {:?}",srulock.entry(trgchatter.clone())),
2024-02-13 19:49:36 -05:00
Some("identity.rs > promote()".to_string()), None);
Log::flush();
}
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(&format!("Target Role : BotAdmin >> Successful"),
2024-02-13 19:49:36 -05:00
Some("identity.rs > promote()".to_string()), None);
return ChangeResult::Success(String::from("Promotion Successful"));
},
2024-02-14 09:21:50 -05:00
Some(_) => {
2024-02-25 10:40:54 -05:00
botinstance::botlog::warn(&format!("Runtime reached undeveloped code"),
2024-02-14 09:21:50 -05:00
Some("identity.rs > promote()".to_string()), None);
},
None => {
2024-02-25 10:40:54 -05:00
botinstance::botlog::warn(&format!("Runtime reached undeveloped code"),
2024-02-14 09:21:50 -05:00
Some("identity.rs > promote()".to_string()), None);
},
2024-02-01 08:40:09 -05:00
}
*/
2024-02-01 08:40:09 -05:00
// 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"));
2024-02-25 10:40:54 -05:00
// }
2024-02-01 08:40:09 -05:00
2024-02-25 10:40:54 -05:00
// // By this point, chatteroles does not contain target role
2024-02-01 08:40:09 -05:00
// // match trgRole {
// // Some(trgRole) => {
// // match trgRole {
// // UserRole::Mod(a) => {
2024-02-25 10:40:54 -05:00
2024-02-01 08:40:09 -05:00
// // },
// // UserRole::SupMod(a) => (),
// // UserRole::BotAdmin => (),
2024-02-25 10:40:54 -05:00
// // _ => (), // <-- do nothing with al other options
2024-02-01 08:40:09 -05:00
// // }
// // },
// // None => {
// // /*
2024-02-25 10:40:54 -05:00
// // - If trgRole is None , then promote by implicit rules . For example,
2024-02-01 08:40:09 -05:00
// // - For UserRoles without Mod or SupMod & Caller is SupMod | Broadcaster | BotAdmin > To Mod
// // - For Mod & Caller is SupMod | Broadcaster | BotAdmin > To SupMod
2024-02-25 10:40:54 -05:00
// // - For UserRoles without BotAdmin & Caller is BotAdmin > To BotAdmin
2024-02-01 08:40:09 -05:00
// // */
// // },
// // }
// // let trgRole = match trgRole {
// // Some(UserRole::Mod(a)) => a,
// // Some(UserRole::SupMod(a)) => a,
// // Some(UserRole::BotAdmin) => UserRole::BotAdmin,
// // None => {
// // /*
2024-02-25 10:40:54 -05:00
// // - If trgRole is None , then promote by implicit rules . For example,
2024-02-01 08:40:09 -05:00
// // - For UserRoles without Mod or SupMod & Caller is SupMod | Broadcaster | BotAdmin > To Mod
// // - For Mod & Caller is SupMod | Broadcaster | BotAdmin > To SupMod
2024-02-25 10:40:54 -05:00
// // - For UserRoles without BotAdmin & Caller is BotAdmin > To BotAdmin
2024-02-01 08:40:09 -05:00
// // */
// // },
// // };
// // 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::
// // }
// },
// _ => (),
// }
2024-02-25 10:40:54 -05:00
botinstance::botlog::warn(
&format!("Runtime reached undeveloped code"),
Some("identity.rs > promote()".to_string()),
None,
);
ChangeResult::Failed(String::from("ERROR"))
2024-02-25 10:40:54 -05:00
}
2024-01-31 21:30:08 -05:00
2024-02-25 10:40:54 -05:00
pub async fn demote(
&self,
authorizer: String,
authorizer_badge: &Option<ChatBadge>,
trgchatter: String,
channel: Option<ChType>,
// trg_role:Option<UserRole>
2024-02-25 10:40:54 -05:00
) -> ChangeResult {
// botinstance::botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?} ; Targer Role {:?}",
2024-02-25 10:40:54 -05:00
// authorizer,trgchatter,channel,trg_role),
botinstance::botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?}",
2024-02-25 10:40:54 -05:00
authorizer,trgchatter,channel), Some("identity.rs > demote()".to_string()), None);
2024-02-14 09:21:50 -05:00
Log::flush();
/*
2024-02-25 10:40:54 -05:00
Check authorizer roles (if any) for the target channel
Check Targer User's roles (if any) for the target channel
Target Channel may be NONE in the case of Non-Channel related roles (FUTURE ENH)
2024-02-14 09:21:50 -05:00
2024-02-25 10:40:54 -05:00
Use the roles of the above to determine whether the authorizer can demote the target user or not
*/
2024-02-14 09:21:50 -05:00
// [x] 1. If Authorizer's Badge is Mod, ensuring Sender is in DB as Mod(Channel)
2024-02-18 16:01:28 -05:00
let trgchatter = trgchatter.to_lowercase();
2024-02-14 09:21:50 -05:00
if let Some(channel) = channel {
2024-02-25 10:40:54 -05:00
let mut authusrroles = self
.getspecialuserroles(authorizer.to_lowercase().clone(), Some(channel.clone()))
2024-02-14 09:21:50 -05:00
.await;
// let authusrroles = authusrroles;
{
// let authusrroles_mut = &mut authusrroles;
// [x] Add Mod(channel) to authusrroles
// [x] #TODO also add to DB if possible?
match *authorizer_badge {
2024-02-25 10:40:54 -05:00
Some(ChatBadge::Mod)
if (!authusrroles.contains(&UserRole::Mod(channel.clone()))
&& !authusrroles.contains(&UserRole::SupMod(channel.clone()))) =>
{
// (*authusrroles_mut).push(UserRole::Mod(channel.clone()));
authusrroles.push(UserRole::Mod(channel.clone()));
2024-02-18 19:23:50 -05:00
// [ ] below pushes mod to authorizer
// 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(channel.clone()));
2024-02-25 10:40:54 -05:00
self.add_role(authorizer.clone(), UserRole::Mod(channel.clone()))
.await;
}
_ => (),
}
}
// [x] 2. Targer User's Vec<UserRole>
2024-02-14 09:21:50 -05:00
2024-02-25 10:40:54 -05:00
let trgusrroles = self
.getspecialuserroles(trgchatter.to_lowercase().clone(), Some(channel.clone()))
2024-02-14 09:21:50 -05:00
.await;
// [x] 3. Return if Authorizer & Target are same chatter and Authorizer is not a BotAdmin
if trgchatter == authorizer && !authusrroles.contains(&UserRole::BotAdmin) {
2024-02-25 10:40:54 -05:00
return ChangeResult::NoChange("Can't target yourself".to_string());
}
// [x] 4a. Authorizers who are BotAdmin, Broadcaster or Supermod can demote a Mod
2024-02-25 10:40:54 -05:00
if (authusrroles.contains(&UserRole::BotAdmin)
|| authusrroles.contains(&UserRole::Broadcaster)
|| authusrroles.contains(&UserRole::SupMod(channel.clone())))
&& trgusrroles.contains(&UserRole::Mod(channel.clone()))
{
// // [ ] Below removes Mod from trgchatter
// let mut srulock = self.special_roles_users.write().await;
// let mut usrrolelock = srulock
// .get_mut(&trgchatter)
// .expect("Error getting roles")
// .write().await;
// if let Some(indx) = usrrolelock.iter().position(|value| *value == UserRole::Mod(channel.clone())){
// usrrolelock.swap_remove(indx);
// return ChangeResult::Success("Demoted successfully".to_string())
// }
self.remove_role(trgchatter.clone(), UserRole::Mod(channel.clone()))
.await;
return ChangeResult::Success("Demoted successfully".to_string());
}
// [x] 4b. Authorizers who are BotAdmin, Broadcaster can demote a SupMod
2024-02-25 10:40:54 -05:00
else if (authusrroles.contains(&UserRole::BotAdmin)
|| authusrroles.contains(&UserRole::Broadcaster))
&& trgusrroles.contains(&UserRole::SupMod(channel.clone()))
{
// [ ] For Trgchatter, below pushes Mod UserRole and removes SupMod
// let mut srulock = self.special_roles_users.write().await;
// let mut usrrolelock = srulock
// .get_mut(&trgchatter)
// .expect("Error getting roles")
// .write().await;
// usrrolelock.push(UserRole::Mod(channel.clone())); // pushes Mod , and removes SupMod
// if let Some(indx) = usrrolelock.iter().position(|value| *value == UserRole::SupMod(channel.clone())){
// usrrolelock.swap_remove(indx);
// return ChangeResult::Success("Demoted successfully".to_string())
// }
2024-02-18 19:23:50 -05:00
2024-02-25 10:40:54 -05:00
self.add_role(trgchatter.clone(), UserRole::Mod(channel.clone()))
.await;
self.remove_role(trgchatter.clone(), UserRole::SupMod(channel.clone()))
.await;
return ChangeResult::Success("Demoted successfully".to_string());
}
// [x] 4c. When Target chatter isnt a Mod or SupMod to demote
2024-02-25 10:40:54 -05:00
else if !trgusrroles.contains(&UserRole::Mod(channel.clone()))
&& !trgusrroles.contains(&UserRole::SupMod(channel.clone()))
{
return ChangeResult::Failed(
"Target chatter does not have a role that can be demoted".to_string(),
);
}
2024-02-18 16:01:28 -05:00
// [x] 4d. When they're only a Mod
else if authusrroles.contains(&UserRole::Mod(channel.clone())) {
2024-02-25 10:40:54 -05:00
return ChangeResult::Failed("You're not permitted to do that".to_string());
}
2024-02-14 09:21:50 -05:00
}
botinstance::botlog::warn(&format!("Potential Unhandled Demotion Condition : Consider explicitely adding in for better handling"),
Some("identity.rs > demote()".to_string()), None);
Log::flush();
2024-02-14 09:21:50 -05:00
ChangeResult::Failed(String::from("Did not meet criteria to demote succesfully"))
2024-01-31 21:30:08 -05:00
}
2024-02-13 19:49:36 -05:00
// pub async fn getspecialuserroles(&self,chattername:String,channel:Option<ChType>) -> Option<Arc<RwLock<Vec<UserRole>>>> {
pub async fn getspecialuserroles(
2024-02-25 10:40:54 -05:00
&self,
chattername: String,
channel: Option<ChType>,
) -> Vec<UserRole> {
2024-02-12 05:25:38 -05:00
/*
2024-02-25 10:40:54 -05:00
Note : Ideally this be called for a given chatter name ?
*/
2024-02-13 19:49:36 -05:00
// [ ] !!! TODO: I don't think below is evaluating by given channel
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!(
"IN VARS > chattername {} ; channel {:?}",
chattername, channel
),
Some("IdentityManager > getspecialuserroles()".to_string()),
None,
);
2024-02-13 19:49:36 -05:00
// resulting vector
let mut evalsproles = vec![];
2024-01-31 21:30:08 -05:00
2024-02-12 05:25:38 -05:00
let chattername = chattername.to_lowercase();
2024-01-31 21:30:08 -05:00
2024-02-13 19:49:36 -05:00
// 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))
2024-02-25 10:40:54 -05:00
} // _ => ()
2024-02-13 19:49:36 -05:00
}
}
None => None,
};
2024-02-12 05:25:38 -05:00
let rolesa = Arc::clone(&self.special_roles_users);
let a = rolesa.read().await;
// let a = Arc::clone(a)
let a = a;
2024-02-13 19:49:36 -05:00
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));
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("INTERNAL > All Roles found {:?}", &a),
Some("IdentityManager > getspecialuserroles()".to_string()),
None,
);
2024-02-13 19:49:36 -05:00
// a.read().await.contains(&UserRole::BotAdmin)
2024-02-25 10:40:54 -05:00
botinstance::botlog::trace(
&format!(
"INTERNAL > eval special roles contains botadmin : {:?}",
a.read().await.contains(&UserRole::BotAdmin)
),
Some("IdentityManager > getspecialuserroles()".to_string()),
None,
);
2024-02-13 19:49:36 -05:00
if a.read().await.contains(&UserRole::BotAdmin) {
evalsproles.push(UserRole::BotAdmin);
2024-02-25 10:40:54 -05:00
}
2024-02-13 19:49:36 -05:00
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()));
2024-02-25 10:40:54 -05:00
}
2024-02-13 19:49:36 -05:00
// else {};
2024-02-25 10:40:54 -05:00
}
2024-02-13 19:49:36 -05:00
None => {
2024-02-25 10:40:54 -05:00
// 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) {
2024-02-13 19:49:36 -05:00
evalsproles.push(UserRole::BotAdmin);
2024-02-25 10:40:54 -05:00
}
2024-02-13 19:49:36 -05:00
}
}
2024-02-25 10:40:54 -05:00
}
2024-02-13 19:49:36 -05:00
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
2024-02-25 10:40:54 -05:00
// In this case, evalsproles would only contain Broadcaster flags if any
}
2024-02-12 05:25:38 -05:00
}
2024-02-04 14:28:37 -05:00
2024-02-25 10:40:54 -05:00
botinstance::botlog::debug(
&format!("OUT > evalsproles {:?}", &evalsproles),
Some("IdentityManager > getspecialuserroles()".to_string()),
None,
);
2024-02-13 19:49:36 -05:00
return evalsproles;
2024-01-31 21:30:08 -05:00
}
2024-01-29 06:18:27 -05:00
}
2024-02-19 21:04:01 -05:00
#[cfg(test)]
mod core_identity {
use casual_logger::Extension;
use super::*;
#[test]
fn user_role_identity() {
Log::set_file_ext(Extension::Log);
// Log::set_level(Level::Trace);
// let result = 2 + 2;
// assert_eq!(result, 4);
2024-02-25 10:40:54 -05:00
assert_eq!(
UserRole::SupMod(ChType::Channel("strong".to_string())),
UserRole::SupMod(ChType::Channel("Strong".to_lowercase()))
);
}
2024-02-19 21:04:01 -05:00
#[tokio::test]
async fn promote_workflow_01() {
Log::set_file_ext(Extension::Log);
// Log::set_level(Level::Trace);
2024-02-25 10:40:54 -05:00
2024-02-19 21:04:01 -05:00
let test_id_mgr = IdentityManager::init();
// [x] Mod Attempts to Promote User
let channel = Some(ChType::Channel("twitchchanneltest".to_string()));
let trgchatter = "regularChatter".to_string();
let authorizer_badge = &Some(ChatBadge::Mod);
let authorizer = "chatMod".to_string();
let trg_role = None;
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.promote(
authorizer,
authorizer_badge,
trgchatter.clone(),
channel.clone(),
trg_role,
)
.await;
assert_eq!(
rslt,
ChangeResult::Failed(String::from("You're not permitted to do that"))
);
}
2024-02-19 21:04:01 -05:00
#[tokio::test]
async fn promote_workflow_02() {
Log::set_file_ext(Extension::Log);
// Log::set_level(Level::Trace);
2024-02-25 10:40:54 -05:00
2024-02-19 21:04:01 -05:00
let test_id_mgr = IdentityManager::init();
// [x] Broadcaster Promotes Chatter to SupMod
let channel = Some(ChType::Channel("broadcasterer".to_string()));
let trgchatter = "regularChatter".to_string();
let authorizer_badge = &Some(ChatBadge::Broadcaster);
let authorizer = "broadcasterer".to_string();
let trg_role = None;
2024-02-25 10:40:54 -05:00
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())
);
let rslt = test_id_mgr
.getspecialuserroles(trgchatter.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
assert!(rslt.contains(&UserRole::Mod(ChType::Channel("broadcasterer".to_string()))));
2024-02-25 10:40:54 -05:00
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())
);
let rslt = test_id_mgr
.getspecialuserroles(trgchatter.clone(), channel.clone())
.await;
assert!(rslt.contains(&UserRole::SupMod(ChType::Channel(
"broadcasterer".to_string()
))));
let rslt = test_id_mgr
.promote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
trg_role.clone(),
)
.await;
assert_eq!(
rslt,
ChangeResult::Failed(String::from("Already highest available role"))
);
2024-02-19 21:04:01 -05:00
}
#[tokio::test]
async fn promote_workflow_03() {
Log::set_file_ext(Extension::Log);
// Log::set_level(Level::Trace);
2024-02-25 10:40:54 -05:00
2024-02-19 21:04:01 -05:00
let test_id_mgr = IdentityManager::init();
// [x] SupMod Promotes Chatter to SupMod
// [x] Broadcaster first promotes a SupMod
2024-02-25 10:40:54 -05:00
2024-02-19 21:04:01 -05:00
let broadcaster = "broadcasterer".to_string();
let broadcaster_badge = &Some(ChatBadge::Broadcaster);
let channel = Some(ChType::Channel(broadcaster.clone()));
let supchatter = "superModerator".to_string();
let trg_role = None;
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.promote(
broadcaster.clone(),
broadcaster_badge,
supchatter.clone(),
channel.clone(),
trg_role.clone(),
)
.await;
assert_eq!(
rslt,
ChangeResult::Success("Promotion Successful".to_string())
);
let rslt = test_id_mgr
.promote(
broadcaster.clone(),
broadcaster_badge,
supchatter.clone(),
channel.clone(),
trg_role.clone(),
)
.await;
assert_eq!(
rslt,
ChangeResult::Success("Promotion Successful".to_string())
);
let rslt = test_id_mgr
.getspecialuserroles(supchatter.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
assert!(rslt.contains(&UserRole::SupMod(channel.unwrap())));
// [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(ChType::Channel(broadcaster.clone()));
let trgchatter = "regularChatter".to_string();
let trg_role = None;
2024-02-25 10:40:54 -05:00
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())
);
let rslt = test_id_mgr
.getspecialuserroles(trgchatter.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
// assert!(rslt.contains(&UserRole::Mod(ChType::Channel("broadcasterer".to_string()))));
assert!(rslt.contains(&UserRole::Mod(channel.clone().unwrap())));
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.promote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
trg_role.clone(),
)
.await;
2024-02-19 21:04:01 -05:00
// assert_eq!(rslt, ChangeResult::Success("Promotion Successful".to_string()));
2024-02-25 10:40:54 -05:00
assert_eq!(
rslt,
ChangeResult::Failed("You're not permitted to do that".to_string())
);
}
2024-02-19 21:04:01 -05:00
#[tokio::test]
async fn promote_workflow_04() {
Log::set_file_ext(Extension::Log);
// Log::set_level(Level::Trace);
2024-02-25 10:40:54 -05:00
2024-02-19 21:04:01 -05:00
let test_id_mgr = IdentityManager::init();
// [x] BotAdmin Promotes Chatter to SupMod
// [x] Create BotAdmin first
let botadmin = "botadministrator".to_string();
let botadmin_badge = &None;
test_id_mgr.affirm_chatter_in_db(botadmin.clone()).await;
2024-02-25 10:40:54 -05:00
test_id_mgr
.add_role(botadmin.clone(), UserRole::BotAdmin)
.await;
2024-02-19 21:04:01 -05:00
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.getspecialuserroles(botadmin.clone(), None)
.await;
2024-02-19 21:04:01 -05:00
2024-02-25 10:40:54 -05:00
assert!(rslt.contains(&UserRole::BotAdmin));
2024-02-19 21:04:01 -05:00
// [x] SupMod Attempts to Promote Chatter to SupMod
// let broadcaster = "broadcasterer".to_string();
let authorizer = botadmin;
let authorizer_badge = botadmin_badge;
let channel = Some(ChType::Channel("somechannel".to_string()));
let trgchatter = "regularChatter".to_string();
let trg_role = None;
2024-02-25 10:40:54 -05:00
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())
);
let rslt = test_id_mgr
.getspecialuserroles(trgchatter.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
assert!(rslt.contains(&UserRole::Mod(channel.clone().unwrap())));
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.promote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
trg_role.clone(),
)
.await;
2024-02-19 21:04:01 -05:00
// assert_eq!(rslt, ChangeResult::Success("Promotion Successful".to_string()));
2024-02-25 10:40:54 -05:00
assert_eq!(
rslt,
ChangeResult::Success("Promotion Successful".to_string())
);
2024-02-19 21:04:01 -05:00
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.getspecialuserroles(trgchatter.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
assert!(rslt.contains(&UserRole::SupMod(channel.clone().unwrap())));
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.promote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
trg_role.clone(),
)
.await;
assert_eq!(
rslt,
ChangeResult::Failed(String::from("Already highest available role"))
);
}
2024-02-19 21:04:01 -05:00
#[tokio::test]
async fn demote_workflow_01() {
Log::set_file_ext(Extension::Log);
// Log::set_level(Level::Trace);
// [x] SupMod demotes a mod
// [x] create a SupMod first
2024-02-25 10:40:54 -05:00
2024-02-19 21:04:01 -05:00
let test_id_mgr = IdentityManager::init();
let supmod = "supmoder".to_string();
// let supmod_badge = &None;
let channel = Some(ChType::Channel("somechannel".to_string()));
test_id_mgr.affirm_chatter_in_db(supmod.clone()).await;
2024-02-25 10:40:54 -05:00
test_id_mgr
.add_role(supmod.clone(), UserRole::SupMod(channel.clone().unwrap()))
.await;
2024-02-19 21:04:01 -05:00
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.getspecialuserroles(supmod.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
assert!(rslt.contains(&UserRole::SupMod(channel.clone().unwrap())));
// [x] Create regular mod
let regmod = "moder".to_string();
// let supmod_badge = &None;
// let channel = Some(ChType::Channel("somechannel".to_string()));
test_id_mgr.affirm_chatter_in_db(regmod.clone()).await;
2024-02-25 10:40:54 -05:00
test_id_mgr
.add_role(regmod.clone(), UserRole::Mod(channel.clone().unwrap()))
.await;
2024-02-19 21:04:01 -05:00
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.getspecialuserroles(regmod.clone(), channel.clone())
.await;
2024-02-19 21:04:01 -05:00
assert!(rslt.contains(&UserRole::Mod(channel.clone().unwrap())));
// [x] Regular mod attempts to demote a supmod
let authorizer = regmod.clone();
let authorizer_badge = &None;
let trgchatter = supmod.clone();
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.demote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
)
.await;
2024-02-19 21:04:01 -05:00
2024-02-25 10:40:54 -05:00
assert_eq!(
rslt,
ChangeResult::Failed("You're not permitted to do that".to_string())
);
2024-02-19 21:04:01 -05:00
// [x] SupMod demotes regular mod
let authorizer = supmod;
let authorizer_badge = &None;
let trgchatter = regmod;
2024-02-25 10:40:54 -05:00
let rslt = test_id_mgr
.demote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
)
.await;
assert_eq!(
rslt,
ChangeResult::Success("Demoted successfully".to_string())
);
let rslt = test_id_mgr
.demote(
authorizer.clone(),
authorizer_badge,
trgchatter.clone(),
channel.clone(),
)
.await;
assert_eq!(
rslt,
ChangeResult::Failed(
"Target chatter does not have a role that can be demoted".to_string()
)
);
2024-02-19 21:04:01 -05:00
}
}