1816 lines
61 KiB
Rust
1816 lines
61 KiB
Rust
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
|
|
use tokio::sync::RwLock;
|
|
|
|
use twitch_irc::message::PrivmsgMessage;
|
|
|
|
use casual_logger::Log;
|
|
|
|
use crate::core::bot_actions::actions_util;
|
|
use crate::core::bot_actions::BotAR;
|
|
use crate::core::botinstance::{Channel,ChangeResult};
|
|
use crate::core::botlog;
|
|
use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager};
|
|
|
|
use dotenv::dotenv;
|
|
use std::env;
|
|
|
|
fn adminvector() -> Vec<String> {
|
|
vec![String::from("ModulatingForce")]
|
|
//vec![]
|
|
}
|
|
|
|
|
|
pub fn otherbots_vector() -> Vec<String> {
|
|
// vec![String::from("ModulatingForce")]
|
|
// //vec![]
|
|
|
|
dotenv().ok();
|
|
let mut other_bots = Vec::new();
|
|
|
|
if let Ok(value) = env::var("OtherBots") {
|
|
for bot in value.split(',') {
|
|
other_bots.push(String::from(bot).to_lowercase())
|
|
}
|
|
}
|
|
|
|
botlog::debug(
|
|
&format!(
|
|
"OtherBots : {:?}",other_bots,
|
|
),
|
|
Some("identity.rs > otherbots_vector()".to_string()),
|
|
None,
|
|
);
|
|
|
|
other_bots
|
|
}
|
|
|
|
|
|
pub async fn init(mgr: Arc<ModulesManager>) {
|
|
botlog::trace(
|
|
"Went into Identity Module init",
|
|
Some("identity.rs > init()".to_string()),
|
|
None,
|
|
);
|
|
|
|
let tempb = BotCommand {
|
|
module: BotModule(String::from("identity")),
|
|
command: String::from("promote"), // command call name
|
|
alias: vec![], // String of alternative names
|
|
exec_body: actions_util::asyncbox(cmd_promote),
|
|
help: String::from("promote"),
|
|
required_roles: vec![
|
|
UserRole::Mod(Channel(String::new())),
|
|
UserRole::SupMod(Channel(String::new())),
|
|
UserRole::Broadcaster,
|
|
UserRole::BotAdmin,
|
|
],
|
|
};
|
|
|
|
// tempb.add_to_modmgr(Arc::clone(&mgr)).await;
|
|
tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
|
|
|
|
async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) {
|
|
botlog::trace(
|
|
"Called cmd promote",
|
|
Some("identity.rs > cmd_prommote()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
// -- If the BotCommand.command was called (e.g., promote) & required roles were validated OUTSIDE of this call
|
|
// , this is the current function body to execute
|
|
|
|
/*
|
|
- `promote` / `demote`
|
|
- [ ] `SupMod` & `Broadcaster` & `BotAdmin` can run
|
|
- [ ] `UserRole`s that can run, can
|
|
- [ ] run `promote` on a regular `Chatter` to make them a `Mod`
|
|
- [ ] run `demote` on a `Mod` to make them a `Chatter`
|
|
- [ ] Only `BotAdmin` can :
|
|
- [ ] target themselves to `promote` / `demote` , in the case that they want to make themselves either a `Mod` or `SupMod` for the channel temporarily
|
|
- [ ] `promote admin <Chatter>` to assign them `BotAdmin` role
|
|
- `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` or `promote` the other way
|
|
*/
|
|
|
|
/*
|
|
Usage :
|
|
|
|
promote <user>
|
|
|
|
demote <user>
|
|
|
|
promote -admin <user>
|
|
|
|
*/
|
|
|
|
// println!("{}",msg.message_text);
|
|
botlog::trace(
|
|
format!("Twich Message > {}", msg.message_text).as_str(),
|
|
Some("identity.rs > cmd_promote()".to_string()),
|
|
None,
|
|
);
|
|
|
|
let sendername = msg.clone().sender.name;
|
|
|
|
let mut argv = msg.message_text.split(' ');
|
|
|
|
argv.next(); // Skip the command name
|
|
|
|
let arg1 = argv.next();
|
|
|
|
let arg2 = argv.next();
|
|
|
|
let mut sender_badge: Option<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);
|
|
}
|
|
}
|
|
|
|
let targetchnl = msg.channel_login.to_lowercase();
|
|
|
|
/*
|
|
|
|
[x] 1. Get trgusr (regardless of -admin flag)
|
|
[x] 2. promote trguser
|
|
[x] 3. Output resulting change
|
|
|
|
*/
|
|
|
|
// [x] 1. Get trgusr (regardless of -admin flag)
|
|
|
|
let targetusr = if arg1 == Some("-admin") { arg2 } else { arg1 };
|
|
|
|
// [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) => {
|
|
botlog::debug(
|
|
"running promote()",
|
|
Some("identity.rs > cmd_promote()".to_string()),
|
|
None,
|
|
);
|
|
Log::flush();
|
|
|
|
let target_bot_admin_role = if arg1 == Some("-admin") {
|
|
Some(UserRole::BotAdmin)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
idlock
|
|
.promote(
|
|
sendername.clone(),
|
|
&sender_badge,
|
|
targetusr.to_string(),
|
|
Some(Channel(targetchnl.clone())),
|
|
target_bot_admin_role,
|
|
)
|
|
.await
|
|
}
|
|
|
|
None => {
|
|
botlog::debug(
|
|
// &format!("No Targer User argument"),
|
|
"No Targer User argument",
|
|
Some("identity.rs > cmd_demote()".to_string()),
|
|
None,
|
|
);
|
|
Log::flush();
|
|
|
|
ChangeResult::NoChange("No Targer User".to_string())
|
|
}
|
|
};
|
|
|
|
// [x] 3. Output resulting change
|
|
|
|
let outmsg = match rslt {
|
|
ChangeResult::Success(a) => {
|
|
format!("o7 Successfully promoted : {a}")
|
|
}
|
|
ChangeResult::Failed(a) => {
|
|
format!("PoroSad failed to promote : {a}")
|
|
}
|
|
ChangeResult::NoChange(a) => {
|
|
format!("uuh No Promotion Change : {a}")
|
|
}
|
|
};
|
|
|
|
botlog::debug(
|
|
outmsg.as_str(),
|
|
Some("identity.rs > cmd_prommote()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
botlock
|
|
.botmgrs
|
|
.chat
|
|
.say_in_reply_to(&msg, outmsg.to_string())
|
|
.await;
|
|
|
|
botlog::trace(
|
|
// &format!("End of cmd_promote()"),
|
|
"End of cmd_promote()",
|
|
Some("identity.rs > cmd_prommote()".to_string()),
|
|
None,
|
|
);
|
|
}
|
|
|
|
let tempb = BotCommand {
|
|
module: BotModule(String::from("identity")),
|
|
command: String::from("demote"), // command call name
|
|
alias: vec![], // String of alternative names
|
|
exec_body: actions_util::asyncbox(cmd_demote),
|
|
help: String::from("demote"),
|
|
required_roles: vec![
|
|
UserRole::Mod(Channel(String::new())),
|
|
UserRole::SupMod(Channel(String::new())),
|
|
UserRole::Broadcaster,
|
|
UserRole::BotAdmin,
|
|
],
|
|
};
|
|
|
|
// tempb.add_to_modmgr(Arc::clone(&mgr)).await;
|
|
// add_core_to_modmgr
|
|
tempb.add_core_to_modmgr(Arc::clone(&mgr)).await;
|
|
|
|
async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) {
|
|
botlog::debug(
|
|
"Called cmd demote",
|
|
Some("identity.rs > cmd_demote()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
Log::flush();
|
|
|
|
// -- If the BotCommand.command was called (e.g., demote) & required roles were validated OUTSIDE of this call
|
|
// , this is the current function body to execute
|
|
|
|
/*
|
|
- `promote` / `demote`
|
|
- [ ] `SupMod` & `Broadcaster` & `BotAdmin` can run
|
|
- [ ] `UserRole`s that can run, can
|
|
- [ ] run `promote` on a regular `Chatter` to make them a `Mod`
|
|
- [ ] run `demote` on a `Mod` to make them a `Chatter`
|
|
- [ ] Only `BotAdmin` can :
|
|
- [ ] target themselves to `promote` / `demote` , in the case that they want to make themselves either a `Mod` or `SupMod` for the channel temporarily
|
|
- [ ] `promote admin <Chatter>` to assign them `BotAdmin` role
|
|
- `[ ] Broadcaster` & `BotAdmin` can `demote` a `SupMod` to make them a `Mod` or `promote` the other way
|
|
*/
|
|
|
|
/*
|
|
Usage :
|
|
|
|
promote <user>
|
|
|
|
demote <user>
|
|
|
|
promote -admin <user>
|
|
|
|
*/
|
|
|
|
// [x] Unwraps arguments from message
|
|
|
|
let (arg1, _arg2) = {
|
|
let mut argv = msg.message_text.split(' ');
|
|
|
|
argv.next(); // Skip the command name
|
|
|
|
let arg1 = argv.next();
|
|
|
|
let arg2 = argv.next();
|
|
|
|
(arg1, arg2)
|
|
};
|
|
|
|
// ---
|
|
|
|
/*
|
|
- [x] 1. Parse out the following
|
|
- Sender (e.g., Name & Badge)
|
|
- Target User (arg1)
|
|
- Target Channel (current channel)
|
|
- Msg or Msg.Message_Text (for later)
|
|
|
|
- [x] 2. Run Demote()
|
|
- within demote(), getspecialuserroles() is called on both the sender and the target
|
|
- getspecialuserroles() only sends current db , while canuserrun() may change db depending on the most current state of the sender
|
|
- getspecialuserroles also borrows the sender's badge to evaluate
|
|
|
|
- [x] 3. Take ChangeResult and output response
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
- [x] 1. Parse out the following
|
|
- Sender (e.g., Name & Badge)
|
|
- Target User (arg1)
|
|
- Target Channel (current channel)
|
|
- (no need) Msg or Msg.Message_Text (for later)
|
|
|
|
*/
|
|
|
|
let sendername = msg.clone().sender.name;
|
|
|
|
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();
|
|
|
|
/*
|
|
|
|
- [x] 2. Run Demote()
|
|
- within demote(), getspecialuserroles() is called on both the sender and the target
|
|
- getspecialuserroles() only sends current db , while canuserrun() may change db depending on the most current state of the sender
|
|
- getspecialuserroles also borrows the sender's badge to evaluate
|
|
|
|
|
|
*/
|
|
|
|
// [x] Get a required lock first
|
|
|
|
let botlock = bot.read().await;
|
|
let id = botlock.get_identity();
|
|
let idlock = id.read().await;
|
|
|
|
let rslt = match targetusr {
|
|
Some(targetusr) => {
|
|
botlog::debug(
|
|
// &format!("running demote()"),
|
|
"running demote()",
|
|
Some("identity.rs > cmd_demote()".to_string()),
|
|
None,
|
|
);
|
|
Log::flush();
|
|
|
|
idlock
|
|
.demote(
|
|
sendername.clone(),
|
|
&sender_badge,
|
|
targetusr.to_string(),
|
|
Some(Channel(targetchnl.clone())),
|
|
)
|
|
.await
|
|
}
|
|
|
|
None => {
|
|
botlog::debug(
|
|
// &format!("No Targer User argument"),
|
|
"No Targer User argument",
|
|
Some("identity.rs > cmd_demote()".to_string()),
|
|
None,
|
|
);
|
|
Log::flush();
|
|
|
|
ChangeResult::NoChange("No Targer User".to_string())
|
|
}
|
|
};
|
|
|
|
/*
|
|
|
|
- [x] 3. Take ChangeResult and output response
|
|
|
|
*/
|
|
|
|
let outmsg = match rslt {
|
|
ChangeResult::Success(a) => {
|
|
format!("o7 Successfully demoted : {a}")
|
|
}
|
|
ChangeResult::Failed(a) => {
|
|
format!("PoroSad failed to demote : {a}")
|
|
}
|
|
ChangeResult::NoChange(a) => {
|
|
format!("uuh No Demotion Change : {a}")
|
|
}
|
|
};
|
|
|
|
botlog::debug(
|
|
outmsg.as_str(),
|
|
Some("identity.rs > cmd_demote()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
botlock
|
|
.botmgrs
|
|
.chat
|
|
.say_in_reply_to(&msg, outmsg.to_string())
|
|
.await;
|
|
}
|
|
|
|
let tempcomm = BotCommand {
|
|
module: BotModule(String::from("identity")),
|
|
command: String::from("getroles"), // command call name
|
|
alias: vec![], // String of alternative names
|
|
exec_body: actions_util::asyncbox(getroles),
|
|
help: String::from("getroles"),
|
|
required_roles: vec![
|
|
UserRole::Mod(Channel(String::new())),
|
|
UserRole::SupMod(Channel(String::new())),
|
|
UserRole::Broadcaster,
|
|
UserRole::BotAdmin,
|
|
],
|
|
};
|
|
|
|
// tempcomm.add_to_modmgr(Arc::clone(&mgr)).await;
|
|
// add_core_to_modmgr
|
|
tempcomm.add_core_to_modmgr(Arc::clone(&mgr)).await;
|
|
|
|
async fn getroles(bot: BotAR, msg: PrivmsgMessage) {
|
|
botlog::debug(
|
|
"Called cmd getroles",
|
|
Some("identity.rs > cmd_getroles()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
/*
|
|
Usage
|
|
|
|
getroles <user> <Channel>
|
|
- If channel is provided, provide roles for that channel specifically
|
|
|
|
*/
|
|
|
|
let mut argv = msg.message_text.split(' ');
|
|
|
|
argv.next(); // Skip the command name
|
|
|
|
let arg1 = argv.next();
|
|
|
|
let targetuser = match arg1 {
|
|
None => return, // exit if no arguments
|
|
Some(arg) => arg,
|
|
};
|
|
|
|
let arg2 = argv.next();
|
|
|
|
let targetchnl = arg2;
|
|
|
|
let botlock = bot.read().await;
|
|
|
|
let id = botlock.get_identity();
|
|
|
|
let idlock = id.read().await;
|
|
|
|
let sproles = match targetchnl {
|
|
None => {
|
|
// [ ] If targetchnl is not provided, default to pulling the current channel
|
|
idlock
|
|
.getspecialuserroles(
|
|
String::from(targetuser),
|
|
Some(Channel(msg.channel_login.to_lowercase())),
|
|
)
|
|
.await
|
|
}
|
|
Some(targetchnl) => {
|
|
// [x] gets special roles for caller
|
|
let callersproles = idlock
|
|
.getspecialuserroles(
|
|
msg.sender.name.to_lowercase(),
|
|
Some(Channel(targetchnl.to_lowercase().to_string())),
|
|
)
|
|
.await;
|
|
|
|
if callersproles.contains(&UserRole::Mod(Channel(
|
|
targetchnl.to_lowercase().to_string(),
|
|
))) || callersproles.contains(&UserRole::SupMod(Channel(
|
|
targetchnl.to_lowercase().to_string(),
|
|
))) || callersproles.contains(&UserRole::Broadcaster)
|
|
{
|
|
idlock
|
|
.getspecialuserroles(
|
|
String::from(targetuser),
|
|
Some(Channel(targetchnl.to_lowercase())),
|
|
)
|
|
.await
|
|
} else {
|
|
// Otherwise, don't get the target channel, return the current channel instead
|
|
idlock
|
|
.getspecialuserroles(
|
|
String::from(targetuser),
|
|
Some(Channel(msg.channel_login.to_lowercase())),
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
};
|
|
|
|
botlog::debug(
|
|
&format!("User roles of Target Chatter >> {:?}", sproles),
|
|
Some("identity.rs > init > getroles()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
botlog::trace(
|
|
// &format!("Evaluating special roles"),
|
|
"Evaluating special roles",
|
|
Some("identity.rs > init > getroles()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
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 = "FeelsWowMan they're the broadcaster. ".to_string();
|
|
|
|
if sproles.contains(&UserRole::Mod(Channel(
|
|
msg.channel_login.to_lowercase(),
|
|
))) || sproles.contains(&UserRole::SupMod(Channel(
|
|
msg.channel_login.to_lowercase(),
|
|
))) || sproles.contains(&UserRole::BotAdmin)
|
|
{
|
|
outmsg += format!("Target chatter's user roles are : {:?}", sproles).as_str();
|
|
}
|
|
outmsg
|
|
} else if sproles.contains(&UserRole::Mod(Channel(
|
|
msg.channel_login.to_lowercase(),
|
|
))) || sproles.contains(&UserRole::SupMod(Channel(
|
|
msg.channel_login.to_lowercase(),
|
|
))) || sproles.contains(&UserRole::BotAdmin)
|
|
{
|
|
format!("Target chatter's user roles are : {:?}", sproles)
|
|
} else {
|
|
"Target chatter has no special roles LULE ".to_string()
|
|
};
|
|
|
|
botlog::debug(
|
|
format!("Chat Say Reply message : {}", outmsg).as_str(),
|
|
Some("identity.rs > init > getroles()".to_string()),
|
|
Some(&msg),
|
|
);
|
|
|
|
botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await;
|
|
|
|
// [ ] NOTE : After the above, I should receive only the roles in the context of the current channel I received this ideally and maybe BotAdmin ; not outside
|
|
}
|
|
|
|
botlog::trace(
|
|
"End of Init MOdule add",
|
|
Some("identity.rs > init ".to_string()),
|
|
None,
|
|
);
|
|
|
|
Log::flush();
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub enum UserRole {
|
|
Chatter,
|
|
Mod(Channel), // String specifies Channel
|
|
SupMod(Channel), // String specifies Channel
|
|
Broadcaster,
|
|
BotAdmin,
|
|
}
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub enum Permissible {
|
|
Allow,
|
|
Block,
|
|
}
|
|
|
|
type UserRolesDB = HashMap<String, Arc<RwLock<Vec<UserRole>>>>;
|
|
|
|
#[derive(Clone)]
|
|
pub struct IdentityManager {
|
|
special_roles_users: Arc<RwLock<UserRolesDB>>,
|
|
}
|
|
/*
|
|
HashMap<
|
|
String, <-- Chatter / Username
|
|
Vec<UserRole> -- <-- Vectors are basically arrays
|
|
>
|
|
*/
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum ChatBadge {
|
|
Broadcaster,
|
|
Mod,
|
|
}
|
|
|
|
// #[derive(Debug, PartialEq, Eq)]
|
|
// pub enum ChangeResult {
|
|
// Success(String),
|
|
// Failed(String),
|
|
// NoChange(String),
|
|
// }
|
|
|
|
impl IdentityManager {
|
|
pub fn init() -> IdentityManager {
|
|
let mut a = HashMap::new();
|
|
for admn in adminvector() {
|
|
a.insert(
|
|
admn.to_lowercase(),
|
|
Arc::new(RwLock::new(vec![UserRole::BotAdmin])),
|
|
);
|
|
}
|
|
|
|
IdentityManager {
|
|
special_roles_users: Arc::new(RwLock::new(a)),
|
|
}
|
|
}
|
|
|
|
// => 03.22 - Force - Made public because botmodules unit tests
|
|
pub async fn add_role(&self, trgchatter: String, trg_role: UserRole) {
|
|
let mut srulock = self.special_roles_users.write().await;
|
|
let mut usrrolelock = srulock
|
|
.get_mut(&trgchatter)
|
|
.expect("Error retrieving roles")
|
|
.write()
|
|
.await;
|
|
usrrolelock.push(trg_role);
|
|
}
|
|
|
|
async fn remove_role(&self, trgchatter: String, trg_role: UserRole) {
|
|
let mut srulock = self.special_roles_users.write().await;
|
|
let mut usrrolelock = srulock
|
|
.get_mut(&trgchatter)
|
|
.expect("Error retrieving roles")
|
|
.write()
|
|
.await;
|
|
if let Some(indx) = usrrolelock.iter().position(|value| *value == trg_role) {
|
|
usrrolelock.swap_remove(indx);
|
|
}
|
|
}
|
|
|
|
// => 03.22 - Force - Made public because botmodules unit tests
|
|
pub async fn affirm_chatter_in_db(&self, trgchatter: String) {
|
|
let mut srulock = self.special_roles_users.write().await;
|
|
srulock
|
|
.entry(trgchatter.clone())
|
|
.or_insert(Arc::new(RwLock::new(vec![])));
|
|
botlog::trace(
|
|
&format!(
|
|
"Ensuring User in Roles {:?}",
|
|
srulock.entry(trgchatter.clone())
|
|
),
|
|
Some("IdentityManager > affirm_chatter_in_db()".to_string()),
|
|
None,
|
|
);
|
|
Log::flush();
|
|
}
|
|
|
|
// [ ] Maybe I should create a can_user_run version that simply takes PrvMsg, but then calls can_user_run directly
|
|
|
|
pub async fn can_user_run_prvmsg(
|
|
&mut self,
|
|
msg: &PrivmsgMessage,
|
|
cmdreqroles: Vec<UserRole>,
|
|
) -> (Permissible, ChangeResult) {
|
|
// [ ] Check what Badges in PrivmsgMessage
|
|
|
|
botlog::trace(
|
|
"Checking within PRVMSG",
|
|
Some("identity.rs > can_user_run_PRVMSG()".to_string()),
|
|
// Some(&msg),
|
|
Some(msg),
|
|
);
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
self.can_user_run(
|
|
msg.sender.name.to_owned(),
|
|
// Channel::construct(msg.channel_login.to_owned()),
|
|
Channel(msg.channel_login.to_owned()),
|
|
sender_badge,
|
|
cmdreqroles,
|
|
)
|
|
.await
|
|
|
|
}
|
|
|
|
pub async fn can_user_run(
|
|
&mut self,
|
|
usr: String,
|
|
channelname: Channel,
|
|
chat_badge: Option<ChatBadge>,
|
|
cmdreqroles: Vec<UserRole>, // ) -> Result<Permissible,Box<dyn Error>> {
|
|
) -> (Permissible, ChangeResult) {
|
|
// println!{"Checking within can_user_run()"};
|
|
botlog::debug(
|
|
&format!(
|
|
"Checking within can_user_run() :
|
|
usr : {} ; channel : {:?} ; badge : {:?} ; cmdreqroles : {:?}",
|
|
usr, channelname, chat_badge, cmdreqroles
|
|
),
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
/*
|
|
canUserRun -
|
|
|
|
Input :
|
|
usr:String,
|
|
channelname:ChType,
|
|
chat_badge:ChatBadge,
|
|
cmdreqroles:Vec<UserRole>
|
|
|
|
Output : Result<Permissible,Box<dyn Error>>
|
|
Some Possible outcomes : Ok(Permissible::Allow) , Ok(Permissible::Block)
|
|
|
|
|
|
Description
|
|
For a Given Chatter (with any special ChatBadge) who ran the Command at a Given Channel , check if that user can
|
|
run the command based on the given cmdreqroles required by the command
|
|
|
|
Inputs and business logic determine if the user can run the command based on the command's required roles
|
|
*/
|
|
|
|
// Requirements
|
|
/*
|
|
[x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow)
|
|
[x] If chatBadge::Broadcaster ...
|
|
[x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow)
|
|
[x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("") , Ok(Permissible::Allow)
|
|
[x] If chatBadge::Mod ...
|
|
[x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType)
|
|
[x] If not, assign them UserRole::Mod(channelname::ChType)
|
|
[x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
|
|
[x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
|
|
[x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow)
|
|
[x] Otherwise, Ok(Permissible::Block)
|
|
*/
|
|
|
|
// [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow)
|
|
|
|
// let idar = Arc::new(RwLock::new(self));
|
|
|
|
let usr = usr.to_lowercase();
|
|
|
|
|
|
let bot_vector = otherbots_vector() ; // result of pulling from Cargo.toml
|
|
|
|
botlog::trace(
|
|
&format!(
|
|
"Checking user is part of known bots: bot_vector.contains(&usr) : {:?}",bot_vector.contains(&usr)
|
|
),
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
if bot_vector.contains(&usr) {
|
|
return (
|
|
Permissible::Block,
|
|
ChangeResult::NoChange("Other Bots Cannot Run Commands".to_string()),
|
|
);
|
|
}
|
|
|
|
// if cmdreqroles.len() == 0 {
|
|
if cmdreqroles.is_empty() {
|
|
// return Ok(Permissible::Allow)
|
|
return (
|
|
Permissible::Allow,
|
|
ChangeResult::NoChange("Command has no required cmdreqroles".to_string()),
|
|
);
|
|
}
|
|
|
|
let mut modrolechange = ChangeResult::NoChange("".to_string());
|
|
|
|
match chat_badge {
|
|
// [x] If chatBadge::Broadcaster ...
|
|
// [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow)
|
|
// [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("") , Ok(Permissible::Allow)
|
|
Some(ChatBadge::Broadcaster) => {
|
|
// if cmdreqroles.contains(&UserRole::Broadcaster)
|
|
// || cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new())))
|
|
// || cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new())))
|
|
// {
|
|
if cmdreqroles.contains(&UserRole::Broadcaster)
|
|
|| cmdreqroles.contains(&UserRole::Mod(Channel(String::new())))
|
|
|| cmdreqroles.contains(&UserRole::SupMod(Channel(String::new())))
|
|
{
|
|
// return Ok(Permissible::Allow)
|
|
return (
|
|
Permissible::Allow,
|
|
ChangeResult::NoChange("Broadcaster Role".to_string()),
|
|
);
|
|
}
|
|
}
|
|
|
|
// [x] If chatBadge::Mod ...
|
|
// [x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType)
|
|
// [x] If not, assign them UserRole::Mod(channelname::ChType)
|
|
Some(ChatBadge::Mod) => {
|
|
botlog::info(
|
|
"Mod Chatbadge detected",
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
let rolesdb = Arc::clone(&self.special_roles_users);
|
|
|
|
self.affirm_chatter_in_db(usr.clone()).await;
|
|
|
|
let rolesdb_lock = rolesdb.write().await;
|
|
|
|
match (*rolesdb_lock).get(&usr.to_lowercase()) {
|
|
Some(usrroles)
|
|
if usrroles
|
|
.read()
|
|
.await
|
|
.contains(&UserRole::Mod(channelname.clone()))
|
|
|| 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
|
|
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...
|
|
|
|
let mut rolesdb_lock_mut = rolesdb_lock;
|
|
let usrroles = rolesdb_lock_mut.get_mut(&usr.to_lowercase()).unwrap();
|
|
let mut usrroles_lock = usrroles.write().await;
|
|
|
|
usrroles_lock.push(UserRole::Mod(channelname.clone()));
|
|
|
|
modrolechange = ChangeResult::Success("Auto Promoted Mod".to_string());
|
|
}
|
|
}
|
|
}
|
|
_ => (), // Don't handle other roles here
|
|
}
|
|
|
|
// [x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
|
|
|
|
botlog::trace(
|
|
&format!("cmd required roles : {:?}", cmdreqroles),
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
// if cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) {
|
|
if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) {
|
|
botlog::trace(
|
|
"Command requires Mod Role",
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
if let Some(a) = self
|
|
.special_roles_users
|
|
.read()
|
|
.await
|
|
.get(&usr.to_lowercase())
|
|
{
|
|
botlog::trace(
|
|
"Special roles found for user",
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
if a.read().await.contains(&UserRole::Mod(channelname.clone()))
|
|
|| a.read()
|
|
.await
|
|
.contains(&UserRole::SupMod(channelname.clone()))
|
|
{
|
|
botlog::trace(
|
|
"> Special Role Identified : Mod ",
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
return (Permissible::Allow, modrolechange);
|
|
}
|
|
}
|
|
}
|
|
|
|
// [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow)
|
|
|
|
// if cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) {
|
|
if cmdreqroles.contains(&UserRole::SupMod(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 (Permissible::Allow, modrolechange);
|
|
}
|
|
}
|
|
}
|
|
|
|
// [x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow)
|
|
|
|
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) {
|
|
botlog::trace(
|
|
format!(
|
|
"special roles get : {:?}",
|
|
self.special_roles_users
|
|
.read()
|
|
.await
|
|
.get(&usr.to_lowercase())
|
|
)
|
|
.as_str(),
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
if let Some(a) = (self)
|
|
.special_roles_users
|
|
.read()
|
|
.await
|
|
.get(&usr.to_lowercase())
|
|
{
|
|
botlog::trace(
|
|
format!(
|
|
"special roles contains BotAdmin: {}",
|
|
a.read().await.contains(&UserRole::BotAdmin)
|
|
)
|
|
.as_str(),
|
|
Some("identity.rs > can_user_run()".to_string()),
|
|
None,
|
|
);
|
|
|
|
if a.read().await.contains(&UserRole::BotAdmin) {
|
|
return (Permissible::Allow, modrolechange);
|
|
}
|
|
}
|
|
}
|
|
|
|
(
|
|
Permissible::Block,
|
|
ChangeResult::NoChange("Not any permissiable condition".to_string()),
|
|
)
|
|
}
|
|
|
|
pub async fn promote(
|
|
&self,
|
|
authorizer: String,
|
|
authorizer_badge: &Option<ChatBadge>,
|
|
trgchatter: String,
|
|
channel: Option<Channel>,
|
|
trg_role: Option<UserRole>,
|
|
) -> ChangeResult {
|
|
botlog::trace(
|
|
&format!(
|
|
"IN VARS for promote() : auth : {} ; authbadge : {:?} ; trg : {} ; Channel {:?} ; {:?}",
|
|
authorizer,authorizer_badge,trgchatter,channel,trg_role),
|
|
Some("identity.rs > promote()".to_string()),
|
|
None,
|
|
);
|
|
Log::flush();
|
|
|
|
/*
|
|
[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
|
|
|
|
|
|
*/
|
|
|
|
// [x] 1. Check if Authorizer Mod Badge then Auto Promote to Mod if not Mod
|
|
|
|
let trgchatter = trgchatter.to_lowercase();
|
|
|
|
let (authusrroles, trgusrroles) = if let Some(channel) = channel.clone() {
|
|
let mut authusrroles = self
|
|
.getspecialuserroles(authorizer.to_lowercase().clone(), Some(channel.clone()))
|
|
.await;
|
|
|
|
{
|
|
match *authorizer_badge {
|
|
Some(ChatBadge::Mod)
|
|
if (!authusrroles.contains(&UserRole::Mod(channel.clone()))
|
|
&& !authusrroles.contains(&UserRole::SupMod(channel.clone()))) =>
|
|
{
|
|
authusrroles.push(UserRole::Mod(channel.clone()));
|
|
|
|
self.affirm_chatter_in_db(authorizer.clone()).await;
|
|
self.add_role(authorizer.clone(), UserRole::Mod(channel.clone()))
|
|
.await;
|
|
}
|
|
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
// [x] 2. Get Authorizer & Target Chatter Roles
|
|
|
|
let trgusrroles = self
|
|
.getspecialuserroles(trgchatter.to_lowercase().clone(), Some(channel.clone()))
|
|
.await;
|
|
|
|
(authusrroles, trgusrroles)
|
|
} else {
|
|
let 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 {
|
|
self.affirm_chatter_in_db(trgchatter.clone()).await;
|
|
|
|
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());
|
|
}
|
|
|
|
/*
|
|
[ ] 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
|
|
*/
|
|
|
|
if let Some(trg_chnl) = channel.clone() {
|
|
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
|
|
// Authorizer must be SupMod,Broadcaster,BotAdmin
|
|
// > Promote target to Mod
|
|
if authusrroles.contains(&UserRole::SupMod(trg_chnl.clone()))
|
|
|| authusrroles.contains(&UserRole::Broadcaster)
|
|
|| authusrroles.contains(&UserRole::BotAdmin)
|
|
{
|
|
self.affirm_chatter_in_db(trgchatter.clone()).await;
|
|
|
|
self.add_role(trgchatter.clone(), UserRole::Mod(trg_chnl.clone()))
|
|
.await;
|
|
|
|
return ChangeResult::Success(String::from("Promotion Successful"));
|
|
} else {
|
|
// Other else conditions would be mostly spcecial responses like ChangeResult::NoChange or ChangeResult::Fail
|
|
// related to authusrroles
|
|
return ChangeResult::Failed(String::from("You're not permitted to do that"));
|
|
}
|
|
} 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
|
|
// Authorizer must be Broadcaster,BotAdmin
|
|
// > Promote target to SupMod
|
|
|
|
if authusrroles.contains(&UserRole::Broadcaster)
|
|
|| authusrroles.contains(&UserRole::BotAdmin)
|
|
{
|
|
self.affirm_chatter_in_db(trgchatter.clone()).await;
|
|
|
|
self.add_role(trgchatter.clone(), UserRole::SupMod(trg_chnl.clone()))
|
|
.await;
|
|
|
|
self.remove_role(trgchatter, UserRole::Mod(trg_chnl.clone()))
|
|
.await;
|
|
|
|
return ChangeResult::Success(String::from("Promotion Successful"));
|
|
} else {
|
|
return ChangeResult::Failed(String::from("You're not permitted to do that"));
|
|
}
|
|
} 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"));
|
|
} else {
|
|
// since handling for channel is already done, will be handling other trguserroles situations here
|
|
|
|
// At the moment, without any new roles, this should not be reached
|
|
|
|
botlog::warn(
|
|
"Code Warning : add handing for other trgusrroles",
|
|
Some("identity.rs > promote()".to_string()),
|
|
None,
|
|
);
|
|
|
|
return ChangeResult::Failed(String::from("Code Warning"));
|
|
}
|
|
};
|
|
|
|
botlog::warn(
|
|
"Runtime reached undeveloped code",
|
|
Some("identity.rs > promote()".to_string()),
|
|
None,
|
|
);
|
|
ChangeResult::Failed(String::from("ERROR"))
|
|
}
|
|
|
|
pub async fn demote(
|
|
&self,
|
|
authorizer: String,
|
|
authorizer_badge: &Option<ChatBadge>,
|
|
trgchatter: String,
|
|
channel: Option<Channel>,
|
|
) -> ChangeResult {
|
|
botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?}",
|
|
authorizer,trgchatter,channel), Some("identity.rs > demote()".to_string()), None);
|
|
Log::flush();
|
|
|
|
/*
|
|
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)
|
|
|
|
Use the roles of the above to determine whether the authorizer can demote the target user or not
|
|
*/
|
|
|
|
// [x] 1. If Authorizer's Badge is Mod, ensuring Sender is in DB as Mod(Channel)
|
|
|
|
let trgchatter = trgchatter.to_lowercase();
|
|
|
|
if let Some(channel) = channel {
|
|
let mut authusrroles = self
|
|
.getspecialuserroles(authorizer.to_lowercase().clone(), Some(channel.clone()))
|
|
.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 {
|
|
Some(ChatBadge::Mod)
|
|
if (!authusrroles.contains(&UserRole::Mod(channel.clone()))
|
|
&& !authusrroles.contains(&UserRole::SupMod(channel.clone()))) =>
|
|
{
|
|
authusrroles.push(UserRole::Mod(channel.clone()));
|
|
|
|
self.add_role(authorizer.clone(), UserRole::Mod(channel.clone()))
|
|
.await;
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
// [x] 2. Targer User's Vec<UserRole>
|
|
|
|
let trgusrroles = self
|
|
.getspecialuserroles(trgchatter.to_lowercase().clone(), Some(channel.clone()))
|
|
.await;
|
|
|
|
// [x] 3. Return if Authorizer & Target are same chatter and Authorizer is not a BotAdmin
|
|
if trgchatter == authorizer && !authusrroles.contains(&UserRole::BotAdmin) {
|
|
return ChangeResult::NoChange("Can't target yourself".to_string());
|
|
}
|
|
|
|
// [x] 4a. Authorizers who are BotAdmin, Broadcaster or Supermod can demote a Mod
|
|
|
|
if (authusrroles.contains(&UserRole::BotAdmin)
|
|
|| authusrroles.contains(&UserRole::Broadcaster)
|
|
|| authusrroles.contains(&UserRole::SupMod(channel.clone())))
|
|
&& trgusrroles.contains(&UserRole::Mod(channel.clone()))
|
|
{
|
|
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
|
|
else if (authusrroles.contains(&UserRole::BotAdmin)
|
|
|| authusrroles.contains(&UserRole::Broadcaster))
|
|
&& trgusrroles.contains(&UserRole::SupMod(channel.clone()))
|
|
{
|
|
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
|
|
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(),
|
|
);
|
|
}
|
|
// [x] 4d. When they're only a Mod
|
|
else if authusrroles.contains(&UserRole::Mod(channel.clone())) {
|
|
return ChangeResult::Failed("You're not permitted to do that".to_string());
|
|
}
|
|
}
|
|
|
|
botlog::warn("Potential Unhandled Demotion Condition : Consider explicitely adding in for better handling",
|
|
Some("identity.rs > demote()".to_string()), None);
|
|
Log::flush();
|
|
ChangeResult::Failed(String::from("Did not meet criteria to demote succesfully"))
|
|
}
|
|
|
|
pub async fn getspecialuserroles(
|
|
&self,
|
|
chattername: String,
|
|
channel: Option<Channel>,
|
|
) -> Vec<UserRole> {
|
|
/*
|
|
Note : Ideally this be called for a given chatter name ?
|
|
*/
|
|
|
|
// [ ] !!! TODO: I don't think below is evaluating by given channel
|
|
botlog::debug(
|
|
&format!(
|
|
"IN VARS > chattername {} ; channel {:?}",
|
|
chattername, channel
|
|
),
|
|
Some("IdentityManager > getspecialuserroles()".to_string()),
|
|
None,
|
|
);
|
|
|
|
// resulting vector
|
|
let mut evalsproles = vec![];
|
|
|
|
let chattername = chattername.to_lowercase();
|
|
|
|
// Checks if broadcaster
|
|
let channel_out = match channel {
|
|
Some(chnl) => {
|
|
// In this block, Some input channel is given
|
|
// We're comparing the channel name with chattername to determine if they're a broadcaster
|
|
if chattername == chnl.0
|
|
{
|
|
evalsproles.push(UserRole::Broadcaster);
|
|
}
|
|
Some(chnl)
|
|
},
|
|
None => None,
|
|
};
|
|
|
|
|
|
let rolesdb = Arc::clone(&self.special_roles_users);
|
|
|
|
let rolesdb_lock = rolesdb.read().await;
|
|
|
|
let vecroles = &(*rolesdb_lock).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) => {
|
|
botlog::debug(
|
|
&format!("INTERNAL > All Roles found {:?}", &a),
|
|
Some("IdentityManager > getspecialuserroles()".to_string()),
|
|
None,
|
|
);
|
|
|
|
botlog::debug(
|
|
&format!(
|
|
"INTERNAL > eval special roles contains botadmin : {:?}",
|
|
a.read().await.contains(&UserRole::BotAdmin)
|
|
),
|
|
Some("IdentityManager > getspecialuserroles()".to_string()),
|
|
None,
|
|
);
|
|
|
|
if a.read().await.contains(&UserRole::BotAdmin) {
|
|
evalsproles.push(UserRole::BotAdmin);
|
|
}
|
|
if a.read().await.contains(&UserRole::Mod(channel.clone())) {
|
|
evalsproles.push(UserRole::Mod(channel.clone()));
|
|
}
|
|
if a.read().await.contains(&UserRole::SupMod(channel.clone())) {
|
|
evalsproles.push(UserRole::SupMod(channel.clone()));
|
|
}
|
|
// else {};
|
|
}
|
|
None => {
|
|
if a.read().await.contains(&UserRole::BotAdmin) {
|
|
evalsproles.push(UserRole::BotAdmin);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
None => {
|
|
// here, the user has no special listed roles. Note though Broadcaster is not stored in special roles
|
|
// Do nothing in this case
|
|
// There may be an issue if the chattername does not exist at the moment in special_roles_users
|
|
// In this case, evalsproles would only contain Broadcaster flags if any
|
|
}
|
|
}
|
|
|
|
botlog::debug(
|
|
&format!("OUT > evalsproles {:?}", &evalsproles),
|
|
Some("IdentityManager > getspecialuserroles()".to_string()),
|
|
None,
|
|
);
|
|
|
|
// return evalsproles;
|
|
evalsproles
|
|
}
|
|
}
|
|
|
|
// =====================
|
|
// =====================
|
|
// =====================
|
|
// =====================
|
|
// =====================
|
|
|
|
#[cfg(test)]
|
|
mod core_identity {
|
|
|
|
use casual_logger::Extension;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn user_role_identity() {
|
|
Log::set_file_ext(Extension::Log);
|
|
assert_eq!(
|
|
UserRole::SupMod(Channel("strong".to_string())),
|
|
UserRole::SupMod(Channel("Strong".to_lowercase()))
|
|
);
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
async fn otherbots_checks() {
|
|
Log::set_file_ext(Extension::Log);
|
|
|
|
let mut test_id_mgr = IdentityManager::init();
|
|
|
|
for bot in otherbots_vector() {
|
|
|
|
let (usr, channelname, chat_badge, cmdreqroles) = (
|
|
bot,
|
|
// Channel::construct("twitchchanneltest".to_string()),
|
|
Channel("twitchchanneltest".to_string()),
|
|
None,
|
|
vec![]
|
|
);
|
|
|
|
let rslt = test_id_mgr.can_user_run(usr, channelname, chat_badge, cmdreqroles).await;
|
|
|
|
assert_eq!(
|
|
(Permissible::Block,
|
|
ChangeResult::NoChange("Other Bots Cannot Run Commands".to_string())),
|
|
rslt
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn promote_workflow_01() {
|
|
Log::set_file_ext(Extension::Log);
|
|
// Log::set_level(Level::Trace);
|
|
|
|
let test_id_mgr = IdentityManager::init();
|
|
|
|
// [x] Mod Attempts to Promote User
|
|
// let channel = Some(Channel::construct("twitchchanneltest".to_string()));
|
|
let channel = Some(Channel("twitchchanneltest".to_string()));
|
|
let trgchatter = "regularChatter".to_string();
|
|
let authorizer_badge = &Some(ChatBadge::Mod);
|
|
let authorizer = "chatMod".to_string();
|
|
let trg_role = None;
|
|
|
|
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"))
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn promote_workflow_02() {
|
|
Log::set_file_ext(Extension::Log);
|
|
// Log::set_level(Level::Trace);
|
|
|
|
let test_id_mgr = IdentityManager::init();
|
|
|
|
// [x] Broadcaster Promotes Chatter to SupMod
|
|
// let channel = Some(Channel::construct("broadcasterer".to_string()));
|
|
let channel = Some(Channel("broadcasterer".to_string()));
|
|
let trgchatter = "regularChatter".to_string();
|
|
let authorizer_badge = &Some(ChatBadge::Broadcaster);
|
|
let authorizer = "broadcasterer".to_string();
|
|
let trg_role = None;
|
|
|
|
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::Mod(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::Success("Promotion Successful".to_string())
|
|
);
|
|
|
|
let rslt = test_id_mgr
|
|
.getspecialuserroles(trgchatter.clone(), channel.clone())
|
|
.await;
|
|
|
|
assert!(rslt.contains(&UserRole::SupMod(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"))
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn promote_workflow_03() {
|
|
Log::set_file_ext(Extension::Log);
|
|
// Log::set_level(Level::Trace);
|
|
|
|
let test_id_mgr = IdentityManager::init();
|
|
|
|
// [x] SupMod Promotes Chatter to SupMod
|
|
|
|
// [x] Broadcaster first promotes a SupMod
|
|
|
|
let broadcaster = "broadcasterer".to_string();
|
|
let broadcaster_badge = &Some(ChatBadge::Broadcaster);
|
|
// let channel = Some(ChType::Channel(broadcaster.clone()));
|
|
let channel = Channel(broadcaster.clone());
|
|
let supchatter = "superModerator".to_string();
|
|
let trg_role = None;
|
|
|
|
let rslt = test_id_mgr
|
|
.promote(
|
|
broadcaster.clone(),
|
|
broadcaster_badge,
|
|
supchatter.clone(),
|
|
Some(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(),
|
|
Some(channel.clone()),
|
|
trg_role.clone(),
|
|
)
|
|
.await;
|
|
|
|
assert_eq!(
|
|
rslt,
|
|
ChangeResult::Success("Promotion Successful".to_string())
|
|
);
|
|
|
|
let rslt = test_id_mgr
|
|
.getspecialuserroles(supchatter.clone(), Some(channel.clone()))
|
|
.await;
|
|
|
|
assert!(rslt.contains(&UserRole::SupMod(channel)));
|
|
|
|
// [x] SupMod Attempts to Promote Chatter to SupMod
|
|
|
|
// let broadcaster = "broadcasterer".to_string();
|
|
let authorizer = supchatter;
|
|
let authorizer_badge = &Some(ChatBadge::Broadcaster);
|
|
let channel = Some(Channel(broadcaster.clone()));
|
|
let trgchatter = "regularChatter".to_string();
|
|
let trg_role = None;
|
|
|
|
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::Mod(channel.clone().unwrap())));
|
|
|
|
let rslt = test_id_mgr
|
|
.promote(
|
|
authorizer.clone(),
|
|
authorizer_badge,
|
|
trgchatter.clone(),
|
|
channel.clone(),
|
|
trg_role.clone(),
|
|
)
|
|
.await;
|
|
|
|
assert_eq!(
|
|
rslt,
|
|
ChangeResult::Failed("You're not permitted to do that".to_string())
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn promote_workflow_04() {
|
|
Log::set_file_ext(Extension::Log);
|
|
// Log::set_level(Level::Trace);
|
|
|
|
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;
|
|
test_id_mgr
|
|
.add_role(botadmin.clone(), UserRole::BotAdmin)
|
|
.await;
|
|
|
|
let rslt = test_id_mgr
|
|
.getspecialuserroles(botadmin.clone(), None)
|
|
.await;
|
|
|
|
assert!(rslt.contains(&UserRole::BotAdmin));
|
|
|
|
// [x] SupMod Attempts to Promote Chatter to SupMod
|
|
|
|
// let broadcaster = "broadcasterer".to_string();
|
|
let authorizer = botadmin;
|
|
let authorizer_badge = botadmin_badge;
|
|
let channel = Some(Channel("somechannel".to_string()));
|
|
let trgchatter = "regularChatter".to_string();
|
|
let trg_role = None;
|
|
|
|
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::Mod(channel.clone().unwrap())));
|
|
|
|
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(channel.clone().unwrap())));
|
|
|
|
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"))
|
|
);
|
|
}
|
|
|
|
#[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
|
|
|
|
let test_id_mgr = IdentityManager::init();
|
|
|
|
let supmod = "supmoder".to_string();
|
|
|
|
let channel = Some(Channel("somechannel".to_string()));
|
|
|
|
test_id_mgr.affirm_chatter_in_db(supmod.clone()).await;
|
|
test_id_mgr
|
|
.add_role(supmod.clone(), UserRole::SupMod(channel.clone().unwrap()))
|
|
.await;
|
|
|
|
let rslt = test_id_mgr
|
|
.getspecialuserroles(supmod.clone(), channel.clone())
|
|
.await;
|
|
|
|
assert!(rslt.contains(&UserRole::SupMod(channel.clone().unwrap())));
|
|
|
|
// [x] Create regular mod
|
|
|
|
let regmod = "moder".to_string();
|
|
|
|
test_id_mgr.affirm_chatter_in_db(regmod.clone()).await;
|
|
test_id_mgr
|
|
.add_role(regmod.clone(), UserRole::Mod(channel.clone().unwrap()))
|
|
.await;
|
|
|
|
let rslt = test_id_mgr
|
|
.getspecialuserroles(regmod.clone(), channel.clone())
|
|
.await;
|
|
|
|
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();
|
|
|
|
let rslt = test_id_mgr
|
|
.demote(
|
|
authorizer.clone(),
|
|
authorizer_badge,
|
|
trgchatter.clone(),
|
|
channel.clone(),
|
|
)
|
|
.await;
|
|
|
|
assert_eq!(
|
|
rslt,
|
|
ChangeResult::Failed("You're not permitted to do that".to_string())
|
|
);
|
|
|
|
// [x] SupMod demotes regular mod
|
|
|
|
let authorizer = supmod;
|
|
let authorizer_badge = &None;
|
|
let trgchatter = regmod;
|
|
|
|
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()
|
|
)
|
|
);
|
|
}
|
|
}
|