2023-12-21 00:48:09 -05:00
/*
2024-02-25 10:40:54 -05:00
ModulesManager is used to manage Modules and BotActions associated with those modules
2023-12-22 09:52:01 -05:00
pub struct ModulesManager {
2024-03-22 15:55:56 -04:00
statusdb : HashMap < BotModule , Vec < ModStatusType > > ,
botactions : HashMap < BotModule , Vec < BotAction > > ,
2023-12-22 09:52:01 -05:00
}
2024-03-22 15:55:56 -04:00
- statusdb : HashMap < BotModule , Vec < ModStatusType > > - Defines Modules and their ModStatusType ( e . g . , Enabled at an Instance level , Disabled at a Channel Level )
- botactions : HashMap < BotModule , Vec < BotAction > > - Defines Modules and their BotActions ( e . g . , BotCommand , Listener , Routine )
2023-12-21 00:48:09 -05:00
Example
{
2024-02-25 10:40:54 -05:00
ModulesManager {
statusdb : { BotModule ( " experiments 004 " ) : [ Enabled ( Instance ) ] } ,
2023-12-22 09:52:01 -05:00
botactions : { BotModule ( " experiments 004 " ) : [ C ( BotCommand { module : BotModule ( " experiments 004 " ) , command : " DUPCMD4 " , alias : [ " DUPALIAS4A " , " DUPALIAS4B " ] , help : " DUPCMD4 tester " } ) ] } }
2023-12-21 00:48:09 -05:00
}
* /
2024-03-25 17:46:57 -04:00
const OF_CMD_CHANNEL :Channel = Channel ( String ::new ( ) ) ;
2024-03-02 10:24:13 -05:00
use core ::panic ;
2023-12-21 00:48:09 -05:00
2024-03-02 10:24:13 -05:00
use std ::collections ::HashMap ;
use std ::sync ::Arc ;
2023-12-21 00:48:09 -05:00
2024-03-22 17:06:09 -04:00
use casual_logger ::Log ;
2024-03-21 14:01:54 -04:00
2024-03-26 11:29:47 -04:00
use chrono ::DateTime ;
2024-03-26 14:30:13 -04:00
// use chrono::Duration;
2024-03-26 11:29:47 -04:00
use chrono ::Local ;
2024-03-02 10:24:13 -05:00
use tokio ::sync ::RwLock ;
use async_trait ::async_trait ;
2024-03-26 11:29:47 -04:00
use tokio ::task ::JoinHandle ;
2024-03-02 10:24:13 -05:00
2024-03-26 14:30:13 -04:00
use tokio ::time ::Instant ;
use tokio ::time ::{ sleep , Duration } ;
2024-03-21 21:20:16 -04:00
use crate ::core ::bot_actions ::actions_util ;
2024-03-24 14:38:09 -04:00
use crate ::core ::bot_actions ::ExecBodyParams ;
2024-03-22 15:55:56 -04:00
use crate ::core ::botinstance ::{ BotInstance , Channel , ChangeResult } ;
2024-03-02 10:24:13 -05:00
use crate ::core ::botlog ;
2024-03-22 17:06:09 -04:00
use crate ::core ::identity ::{ self , Permissible , IdentityManager } ;
2024-02-12 01:25:12 -05:00
2024-03-02 12:21:18 -05:00
use crate ::core ::bot_actions ;
2024-03-22 15:55:56 -04:00
2024-03-22 20:18:02 -04:00
use std ::hash ::{ Hash , Hasher } ;
2024-03-21 21:20:16 -04:00
use super ::identity ::ChatBadge ;
2024-03-21 00:05:52 -04:00
2024-03-21 21:20:16 -04:00
pub async fn init ( mgr : Arc < ModulesManager > ) {
// 1. Define the BotAction
let botc1 = BotCommand {
module : BotModule ( String ::from ( " core " ) ) ,
command : String ::from ( " enable " ) , // command call name
alias : vec ! [
String ::from ( " e " ) ,
String ::from ( " en " ) ] , // String of alternative names
exec_body : actions_util ::asyncbox ( cmd_enable ) ,
help : String ::from ( " Test Command tester " ) ,
required_roles : vec ! [
identity ::UserRole ::BotAdmin ,
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ,
} ;
// 2. Add the BotAction to ModulesManager
botc1 . add_core_to_modmgr ( Arc ::clone ( & mgr ) ) . await ;
2024-03-24 14:38:09 -04:00
// async fn cmd_enable(bot: BotAR, msg: PrivmsgMessage) {
async fn cmd_enable ( params : ExecBodyParams ) {
2024-03-21 21:20:16 -04:00
/*
There should be additional validation checks
- BotAdmins can only run instance level ( - i ) enables
2024-03-22 08:21:10 -04:00
- If BotAdmins need to enable / disable at Channel level , they must Promote themselves to be a Mod at least
2024-03-21 21:20:16 -04:00
- Other Special Roles ( Mod , SupMod , Broadcaster ) can run without issues to enable the module at Channel Level
* /
/*
enable - i < module > // enables at Instance
enable < module > // enables at Channel
* /
/*
1. Parse out Message Arguments
exec_enable ( )
2. Get Special Roles of CmdSender
3. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
3 a . , and is not - i ( to instance ) , return a Failure recommending BotAdmin promote themselves first
3 b . , and is - i ( to instance ) , return a Success
4. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
4 a . , and is not - i ( to instance ) , return a Success
4 b . , and is - i ( to instance ) , return a Failure they are not allowed
5. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
5 a . , and is not - i ( to instance ) , return a Success
5 b . , and is - i ( to instance ) , return a Success
* /
2024-03-22 08:21:10 -04:00
2024-03-22 18:02:31 -04:00
// [x] Unwraps arguments from message
2024-03-22 08:21:10 -04:00
let ( arg1 , arg2 ) = {
2024-03-24 14:38:09 -04:00
let mut argv = params . msg . message_text . split ( ' ' ) ;
2024-03-22 08:21:10 -04:00
argv . next ( ) ; // Skip the command name
let arg1 = argv . next ( ) ;
let arg2 = argv . next ( ) ;
( arg1 , arg2 )
} ;
/* -- Related function to call later
exec_enable (
& self ,
requestor : String ,
requestor_badge : Option < ChatBadge > ,
2024-03-22 15:55:56 -04:00
trg_module : BotModule ,
// channel: Option<Channel>,
2024-03-22 08:21:10 -04:00
trg_level : StatusLvl ,
bot : BotAR ,
) -> ChangeResult
2024-03-21 21:20:16 -04:00
* /
2024-03-22 18:02:31 -04:00
// [x] requestor: String,
2024-03-24 14:38:09 -04:00
let requestor = params . msg . clone ( ) . sender . name ;
2024-03-22 08:21:10 -04:00
2024-03-22 18:02:31 -04:00
// [x] requestor_badge: Option<ChatBadge>,
2024-03-22 08:21:10 -04:00
let mut requestor_badge_mut : Option < ChatBadge > = None ;
2024-03-24 14:38:09 -04:00
for b in & params . msg . badges {
2024-03-22 08:21:10 -04:00
if b . name = = " moderator " {
requestor_badge_mut = Some ( ChatBadge ::Mod ) ;
} else if b . name = = " broadcaster " {
requestor_badge_mut = Some ( ChatBadge ::Broadcaster ) ;
2024-03-25 17:01:27 -04:00
} else if b . name = = " vip " {
requestor_badge_mut = Some ( ChatBadge ::VIP ) ;
2024-03-22 08:21:10 -04:00
}
}
let requestor_badge = requestor_badge_mut ;
2024-03-22 15:55:56 -04:00
// [x] trg_module: BotModule,
// - [x] Need to validate an actual BotModule - otherwise, fail or exit the cmd
2024-03-22 08:21:10 -04:00
let trg_module = if ( arg1 = = Some ( " -i " ) ) | | ( arg1 = = Some ( " -f " ) ) { arg2 } else { arg1 } ;
2024-03-22 18:02:31 -04:00
// if no trg_module was passed
2024-03-22 20:18:02 -04:00
// if let None = trg_module {
if trg_module . is_none ( ) {
2024-03-22 08:21:10 -04:00
2024-03-25 15:46:37 -04:00
// let botlock = params.bot.read().await;
2024-03-22 18:02:31 -04:00
let outmsg = " uuh You need to pass a module " ;
2024-03-22 08:21:10 -04:00
2024-03-22 18:02:31 -04:00
botlog ::debug (
outmsg ,
Some ( " botmodules.rs > cmd_enable() " . to_string ( ) ) ,
2024-03-24 14:38:09 -04:00
Some ( & params . msg ) ,
2024-03-22 18:02:31 -04:00
) ;
2024-03-24 16:59:50 -04:00
2024-03-25 14:11:21 -04:00
// We should call a notification around here
let bot = params . clone ( ) . bot ;
let botclone = Arc ::clone ( & bot ) ;
let botlock = botclone . read ( ) . await ;
botlock . botmgrs . chat . send_botmsg ( super ::chat ::BotMsgType ::Notif (
outmsg . to_string ( )
) ,
params . clone ( ) ,
) . await ;
2024-03-22 18:02:31 -04:00
return ;
2024-03-22 08:21:10 -04:00
}
2024-03-22 18:02:31 -04:00
// [x] trg_level: StatusLvl,
2024-03-22 08:21:10 -04:00
2024-03-24 14:38:09 -04:00
let currchnl = params . msg . channel_login . to_lowercase ( ) ;
2024-03-22 08:21:10 -04:00
let trg_level =
2024-03-22 20:18:02 -04:00
if arg1 = = Some ( " -i " ) | | arg1 = = Some ( " -f " ) { StatusLvl ::Instance }
2024-03-22 15:55:56 -04:00
else { StatusLvl ::Ch ( Channel ( currchnl ) ) }
2024-03-22 08:21:10 -04:00
;
2024-03-22 18:02:31 -04:00
2024-03-24 14:38:09 -04:00
let botlock = params . bot . read ( ) . await ;
2024-03-22 18:02:31 -04:00
let modmgr = Arc ::clone ( & botlock . botmodules ) ;
let id = botlock . get_identity ( ) ;
let rslt = modmgr . exec_enable (
requestor ,
requestor_badge ,
2024-03-22 15:55:56 -04:00
BotModule ( trg_module . unwrap ( ) . to_string ( ) ) ,
2024-03-22 18:02:31 -04:00
trg_level ,
id ) . await ;
2024-03-25 14:11:21 -04:00
// We should call a notification around here
2024-03-22 18:02:31 -04:00
let outmsg = match rslt . clone ( ) {
ChangeResult ::Failed ( a ) = > format! ( " Stare Failed : {} " , a ) ,
ChangeResult ::NoChange ( a ) = > format! ( " Hmm No Change : {} " , a ) ,
ChangeResult ::Success ( a ) = > format! ( " YAAY Success : {} " , a ) ,
} ;
2024-03-22 08:21:10 -04:00
2024-03-25 14:11:21 -04:00
botlock . botmgrs . chat . send_botmsg ( super ::chat ::BotMsgType ::Notif (
outmsg . to_string ( )
) ,
params . clone ( ) ,
) . await ;
2024-03-25 16:08:24 -04:00
2024-03-22 18:16:41 -04:00
2024-03-21 21:20:16 -04:00
}
// 1. Define the BotAction
let botc1 = BotCommand {
module : BotModule ( String ::from ( " core " ) ) ,
command : String ::from ( " disable " ) , // command call name
alias : vec ! [
String ::from ( " d " ) ] , // String of alternative names
exec_body : actions_util ::asyncbox ( cmd_disable ) ,
help : String ::from ( " Test Command tester " ) ,
required_roles : vec ! [
identity ::UserRole ::BotAdmin ,
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ,
} ;
// 2. Add the BotAction to ModulesManager
botc1 . add_core_to_modmgr ( Arc ::clone ( & mgr ) ) . await ;
2024-03-24 14:38:09 -04:00
// async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) {
async fn cmd_disable ( params : ExecBodyParams ) {
2024-03-21 21:20:16 -04:00
/*
There should be additional validation checks
2024-03-22 08:21:10 -04:00
- BotAdmins can only run instance level ( - i ) disables and ( - f ) force disable
- If BotAdmins need to enable / disable at Channel level , they must Promote themselves to be a Mod at least
2024-03-21 21:20:16 -04:00
- Other Special Roles ( Mod , SupMod , Broadcaster ) can run without issues to disable the module at Channel Level
2024-03-22 08:21:10 -04:00
* /
2024-03-21 21:20:16 -04:00
/*
disable - i < module > // disables at Instance
disable < module > // disables at Channel
disable - f < module > // force disables (instance and enabled are removed)
* /
2024-03-22 08:21:10 -04:00
/*
1. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
1 a . , and has no special flags ( - i / - f ) , return a Failure recommending BotAdmin promote themselves first
1 b . , and is - i ( to instance ) , return a Success
1 c . , and is - f ( forced ) , return a Success
2. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
2 a . , and has no special flags ( - i / - f ) , return a Success
2 b . , and is - i ( to instance ) , return a Failure they are not allowed
2 c . , and is - f ( forced ) , return a Failure they are not allowed
3. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
3. can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster ) & can_user_run for cmdreqRoles including BotAdmin
3 a . , and has no special flags ( - i / - f ) , return a Success
3 b . , and is - i ( to instance ) , return a Success
3 c . , and is - f ( forced ) , return a Success
* /
2024-03-21 21:20:16 -04:00
2024-03-24 16:59:50 -04:00
2024-03-25 16:08:24 -04:00
// [x] Unwraps arguments from message
2024-03-22 18:16:41 -04:00
let ( arg1 , arg2 ) = {
2024-03-24 14:38:09 -04:00
let mut argv = params . msg . message_text . split ( ' ' ) ;
2024-03-22 18:16:41 -04:00
argv . next ( ) ; // Skip the command name
let arg1 = argv . next ( ) ;
let arg2 = argv . next ( ) ;
( arg1 , arg2 )
} ;
/* -- Related function to call later
exec_disable (
& self ,
requestor : String ,
requestor_badge : Option < ChatBadge > ,
2024-03-22 15:55:56 -04:00
trg_module : BotModule ,
// channel: Option<Channel>,
2024-03-22 18:16:41 -04:00
trg_level : StatusLvl ,
force : bool ,
// bot: BotAR,
id : Arc < RwLock < IdentityManager > > ,
) -> ChangeResult
* /
// [x] requestor: String,
2024-03-24 14:38:09 -04:00
let requestor = params . msg . clone ( ) . sender . name ;
2024-03-22 18:16:41 -04:00
// [x] requestor_badge: Option<ChatBadge>,
let mut requestor_badge_mut : Option < ChatBadge > = None ;
2024-03-24 14:38:09 -04:00
for b in & params . msg . badges {
2024-03-22 18:16:41 -04:00
if b . name = = " moderator " {
requestor_badge_mut = Some ( ChatBadge ::Mod ) ;
} else if b . name = = " broadcaster " {
requestor_badge_mut = Some ( ChatBadge ::Broadcaster ) ;
2024-03-25 17:01:27 -04:00
} else if b . name = = " vip " {
requestor_badge_mut = Some ( ChatBadge ::VIP ) ;
2024-03-22 18:16:41 -04:00
}
}
let requestor_badge = requestor_badge_mut ;
2024-03-22 15:55:56 -04:00
// [x] trg_module: BotModule,
// - [x] Need to validate an actual BotModule - otherwise, fail or exit the cmd
2024-03-22 18:16:41 -04:00
let trg_module = if ( arg1 = = Some ( " -i " ) ) | | ( arg1 = = Some ( " -f " ) ) { arg2 } else { arg1 } ;
// if no trg_module was passed
2024-03-22 20:18:02 -04:00
if trg_module . is_none ( ) {
2024-03-22 18:16:41 -04:00
2024-03-24 14:38:09 -04:00
let botlock = params . bot . read ( ) . await ;
2024-03-22 18:16:41 -04:00
let outmsg = " uuh You need to pass a module " ;
botlog ::debug (
outmsg ,
Some ( " botmodules.rs > cmd_disable() " . to_string ( ) ) ,
2024-03-24 14:38:09 -04:00
Some ( & params . msg ) ,
2024-03-22 18:16:41 -04:00
) ;
2024-03-24 16:59:50 -04:00
2024-03-25 14:11:21 -04:00
// We should call a notification around here
2024-03-24 16:59:50 -04:00
2024-03-25 14:11:21 -04:00
botlock . botmgrs . chat . send_botmsg ( super ::chat ::BotMsgType ::Notif (
outmsg . to_string ( )
) ,
params . clone ( ) ,
) . await ;
2024-03-24 16:59:50 -04:00
2024-03-22 18:16:41 -04:00
return ;
}
// [x] trg_level: StatusLvl,
2024-03-24 14:38:09 -04:00
let currchnl = params . msg . channel_login . to_lowercase ( ) ;
2024-03-22 18:16:41 -04:00
let trg_level =
2024-03-22 20:18:02 -04:00
if arg1 = = Some ( " -i " ) | | arg1 = = Some ( " -f " ) { StatusLvl ::Instance }
// else if arg1 == Some("-f") { StatusLvl::Instance }
2024-03-22 15:55:56 -04:00
else { StatusLvl ::Ch ( Channel ( currchnl ) ) }
2024-03-22 18:16:41 -04:00
;
2024-03-24 14:38:09 -04:00
let botlock = params . bot . read ( ) . await ;
2024-03-22 18:16:41 -04:00
let modmgr = Arc ::clone ( & botlock . botmodules ) ;
let id = botlock . get_identity ( ) ;
let force = arg1 = = Some ( " -f " ) ;
let rslt = modmgr . exec_disable (
requestor ,
requestor_badge ,
2024-03-22 15:55:56 -04:00
BotModule ( trg_module . unwrap ( ) . to_string ( ) ) ,
2024-03-22 18:16:41 -04:00
trg_level ,
force ,
id ) . await ;
2024-03-22 18:49:07 -04:00
2024-03-22 18:16:41 -04:00
let outmsg = match rslt . clone ( ) {
ChangeResult ::Failed ( a ) = > format! ( " Stare Failed : {} " , a ) ,
ChangeResult ::NoChange ( a ) = > format! ( " Hmm No Change : {} " , a ) ,
ChangeResult ::Success ( a ) = > format! ( " YAAY Success : {} " , a ) ,
} ;
2024-03-25 14:11:21 -04:00
// We should call a notification around here
2024-03-24 16:59:50 -04:00
2024-03-25 14:11:21 -04:00
botlock . botmgrs . chat . send_botmsg ( super ::chat ::BotMsgType ::Notif (
outmsg . to_string ( )
) ,
params . clone ( ) ,
) . await ;
2024-03-24 16:59:50 -04:00
2024-03-21 21:20:16 -04:00
}
}
2024-03-22 20:18:02 -04:00
#[ derive(Debug, Clone) ]
2024-03-23 14:00:20 -04:00
pub struct BotModule ( pub String ) ;
2024-03-23 13:33:45 -04:00
2024-03-22 15:55:56 -04:00
impl PartialEq for BotModule {
2024-03-22 08:40:09 -04:00
fn eq ( & self , other : & Self ) -> bool {
let BotModule ( name1 ) = self . clone ( ) ;
let BotModule ( name2 ) = other . clone ( ) ;
name1 . to_lowercase ( ) = = name2 . to_lowercase ( )
}
}
2024-03-22 15:55:56 -04:00
impl Eq for BotModule { }
2024-03-22 08:40:09 -04:00
2024-03-22 15:55:56 -04:00
impl Hash for BotModule {
2024-03-22 20:18:02 -04:00
fn hash < H : Hasher > ( & self , state : & mut H ) {
let BotModule ( name ) = self . clone ( ) ;
name . to_lowercase ( ) . hash ( state ) ;
}
}
2024-03-22 08:40:09 -04:00
2024-03-20 23:20:46 -04:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone) ]
pub enum ModGroup {
Core ,
Custom ,
}
2024-03-21 02:13:23 -04:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone) ]
2024-03-01 23:36:37 -05:00
pub enum StatusLvl {
2023-12-21 00:48:09 -05:00
Instance ,
2024-03-22 15:55:56 -04:00
Ch ( Channel ) ,
2023-12-21 00:48:09 -05:00
}
2024-03-21 02:13:23 -04:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone) ]
2024-03-20 23:35:56 -04:00
pub enum StatusType {
2023-12-21 00:48:09 -05:00
Enabled ( StatusLvl ) ,
Disabled ( StatusLvl ) ,
}
2024-02-04 14:28:37 -05:00
2024-02-25 10:40:54 -05:00
pub enum BotAction {
C ( BotCommand ) ,
2024-01-29 01:13:56 -05:00
L ( Listener ) ,
2024-02-25 10:40:54 -05:00
R ( Routine ) ,
2023-12-21 00:48:09 -05:00
}
2023-12-26 20:00:32 -05:00
2024-01-29 02:27:11 -05:00
impl BotAction {
2024-03-24 14:38:09 -04:00
pub async fn execute ( & self , params : ExecBodyParams ) {
2024-01-29 02:27:11 -05:00
match self {
2024-03-24 14:38:09 -04:00
BotAction ::L ( a ) = > a . execute ( params ) . await ,
BotAction ::C ( a ) = > a . execute ( params ) . await ,
2024-01-29 02:27:11 -05:00
_ = > ( ) ,
}
}
}
2024-02-04 14:28:37 -05:00
#[ async_trait ]
2024-02-25 10:40:54 -05:00
pub trait BotActionTrait {
async fn add_to_bot ( self , bot : BotInstance ) ;
async fn add_to_modmgr ( self , modmgr : Arc < ModulesManager > ) ;
2024-03-20 23:20:46 -04:00
async fn add_core_to_bot ( self , bot : BotInstance ) ;
async fn add_core_to_modmgr ( self , modmgr : Arc < ModulesManager > ) ;
2023-12-26 20:00:32 -05:00
}
2024-01-29 04:09:53 -05:00
pub struct BotCommand {
2024-03-22 15:55:56 -04:00
pub module : BotModule ,
2024-02-25 10:40:54 -05:00
pub command : String , // command call name
pub alias : Vec < String > , // String of alternative names
pub exec_body : bot_actions ::actions_util ::ExecBody ,
pub help : String ,
pub required_roles : Vec < identity ::UserRole > ,
2024-01-29 04:09:53 -05:00
}
2024-02-25 10:40:54 -05:00
impl BotCommand {
2024-03-24 14:38:09 -04:00
pub async fn execute ( & self , params : ExecBodyParams ) {
( * self . exec_body ) ( params ) . await ;
2024-01-29 04:09:53 -05:00
}
}
2024-02-04 14:28:37 -05:00
#[ async_trait ]
2024-02-25 10:40:54 -05:00
impl BotActionTrait for BotCommand {
async fn add_to_bot ( self , bot : BotInstance ) {
2024-02-12 05:25:38 -05:00
self . add_to_modmgr ( bot . botmodules ) . await ;
2024-01-29 04:09:53 -05:00
}
2024-02-25 10:40:54 -05:00
async fn add_to_modmgr ( self , modmgr : Arc < ModulesManager > ) {
modmgr
. add_botaction ( self . module . clone ( ) , BotAction ::C ( self ) )
. await
2024-01-29 04:09:53 -05:00
}
2024-03-20 23:20:46 -04:00
async fn add_core_to_bot ( self , bot : BotInstance ) {
self . add_core_to_modmgr ( bot . botmodules ) . await ;
}
async fn add_core_to_modmgr ( self , modmgr : Arc < ModulesManager > ) {
modmgr
. add_core_act ( self . module . clone ( ) , BotAction ::C ( self ) )
. await
}
2024-01-29 04:09:53 -05:00
}
2024-02-25 10:40:54 -05:00
pub struct Listener {
2024-03-22 15:55:56 -04:00
pub module : BotModule ,
2024-02-25 10:40:54 -05:00
pub name : String ,
pub exec_body : bot_actions ::actions_util ::ExecBody ,
pub help : String ,
2023-12-21 00:48:09 -05:00
}
2024-02-25 10:40:54 -05:00
impl Listener {
2024-03-24 14:38:09 -04:00
pub async fn execute ( & self , params : ExecBodyParams ) {
( self . exec_body ) ( params ) . await ;
2023-12-26 20:00:32 -05:00
}
}
2024-02-04 14:28:37 -05:00
#[ async_trait ]
2024-02-25 10:40:54 -05:00
impl BotActionTrait for Listener {
async fn add_to_bot ( self , bot : BotInstance ) {
2024-03-02 10:06:26 -05:00
botlog ::trace (
2024-02-25 10:40:54 -05:00
" Adding action to bot " ,
Some ( " BotModules > BotActionTrait > add_to_bot() " . to_string ( ) ) ,
None ,
) ;
2024-02-12 02:34:32 -05:00
self . add_to_modmgr ( bot . botmodules ) . await ;
2023-12-26 20:00:32 -05:00
}
2024-02-25 10:40:54 -05:00
async fn add_to_modmgr ( self , modmgr : Arc < ModulesManager > ) {
2024-03-02 10:06:26 -05:00
botlog ::trace (
2024-02-25 10:40:54 -05:00
" Adding action to module manager " ,
Some ( " BotModules > BotActionTrait > add_to_bot() " . to_string ( ) ) ,
None ,
) ;
2024-02-13 07:54:35 -05:00
2024-02-25 10:40:54 -05:00
modmgr
. add_botaction ( self . module . clone ( ) , BotAction ::L ( self ) )
. await ;
2023-12-26 20:00:32 -05:00
}
2024-03-20 23:20:46 -04:00
async fn add_core_to_bot ( self , bot : BotInstance ) {
self . add_core_to_modmgr ( bot . botmodules ) . await ;
}
async fn add_core_to_modmgr ( self , modmgr : Arc < ModulesManager > ) {
modmgr
. add_core_act ( self . module . clone ( ) , BotAction ::L ( self ) )
. await
}
2023-12-26 20:00:32 -05:00
}
2024-03-26 14:30:13 -04:00
// #[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[ derive(PartialEq, Eq, Hash) ]
pub enum RoutineAttr {
2024-03-26 11:29:47 -04:00
DelayedStart ,
ScheduledStart ( DateTime < Local > ) , // Scheduled Date (if any) after which, if not started, may trigger
LoopDuration ( Duration ) , // How long to wait between iterations
LoopInfinitely ,
RunOnce ,
MaxTimeThreshold ( DateTime < Local > ) , // DateTime after which, it will abort/cancel or stop
MaxIterations ( i64 ) ,
}
/*
a Routine can be given different combinations of the above , but business logic may validate
these at Routine construction
For example , a Routine could have the following characteristics
- DelayedStart ( so it skips the first iteration )
- ScheduledStart ( DateTime < Local > ) - With a Start Date - Time for the first iteration to trigger
- LoopDuration ( Duration ) - How long to wait between iterations
The above without any other thresholds would loop infinitely with the above characteristics
Another example ,
- LoopDuration ( Duration ) - How long to wait between iterations
- MaxTimeThreshold ( DateTime < Local > )
- MaxIterations ( i64 )
The above has thresholds , so if either are reached , it would abort / cancel or stop . Since there is no
ScheduledStart , the routine would have to be started manually elsewhere
Another example ,
- ( no RoutineAttr )
The above would only run once , and only when the Start ( ) is called
* /
// #[derive(Debug)]
pub struct Routine {
2024-03-26 14:30:13 -04:00
pub name : String ,
2024-03-26 11:29:47 -04:00
module : BotModule , // from() can determine this if passed parents_params
// pub channel : Option<Channel> , // Routines generally run by Channel ; but can be left None
channel : Channel , // Requiring some channel context
exec_body : bot_actions ::actions_util ::ExecBody ,
2024-03-26 14:30:13 -04:00
// parent_params : Option<ExecBodyParams> ,
parent_params : ExecBodyParams ,
2024-03-26 11:29:47 -04:00
join_handle : Option < JoinHandle < ( ) > > ,
start_time : Option < DateTime < Local > > ,
2024-03-26 14:30:13 -04:00
complete_iterations : i64 ,
remaining_iterations : Option < i64 > ,
2024-03-26 11:29:47 -04:00
routine_attr : Vec < RoutineAttr > ,
}
impl Routine {
// Constructor
pub fn from (
2024-03-26 14:30:13 -04:00
name : String ,
module : BotModule ,
channel : Channel ,
routine_attr : Vec < RoutineAttr > ,
exec_body : bot_actions ::actions_util ::ExecBody ,
// parent_params : Option<ExecBodyParams>
parent_params : ExecBodyParams
// ) -> Result<String,String> {
) -> Result < Routine , String > {
2024-03-26 11:29:47 -04:00
// [ ] Validation is made against parent_params
// to ensure those params don't conflict
// conlicts would throw an error
2024-03-26 14:30:13 -04:00
// parent_params.unwrap().
if routine_attr . contains ( & RoutineAttr ::RunOnce ) {
return Ok ( Routine {
name ,
module ,
channel ,
exec_body ,
parent_params ,
join_handle : None ,
start_time : None ,
complete_iterations : 0 ,
remaining_iterations : None ,
routine_attr : routine_attr
} ) ;
}
2024-03-26 11:29:47 -04:00
Err ( " NOT IMPLEMENTED " . to_string ( ) )
}
pub fn change_channel (
& self ,
_channel : Channel
) -> Result < String , String > {
// [ ] Think Ideally it should try to
// change the target channel of the
// internal process too if possible?
Err ( " NOT IMPLEMENTED " . to_string ( ) )
}
2024-03-26 14:30:13 -04:00
pub async fn start ( self ) -> Result < String , String >
2024-03-26 11:29:47 -04:00
{
// [ ] Asyncio Spawn likely around here
// [ ] & Assigns self.join_handle
2024-03-26 14:30:13 -04:00
let self_rw = Arc ::new ( RwLock ::new ( self ) ) ;
let mut self_wr_lock = self_rw . write ( ) . await ;
if self_wr_lock . routine_attr . contains ( & RoutineAttr ::RunOnce ) {
self_wr_lock . remaining_iterations = Some ( 1 ) ;
fn innerhelper ( self_rw : Arc < RwLock < Routine > > ) -> Option < JoinHandle < ( ) > > {
Some (
tokio ::spawn ( async move {
let mut self_wr_lock = self_rw . write ( ) . await ;
let mut remainingiter = self_wr_lock . remaining_iterations . unwrap ( ) ;
botlog ::trace (
format! (
" [TRACE][Routine Started] {} in {} " ,
self_wr_lock . name , self_wr_lock . channel . 0
)
. as_str ( ) ,
Some ( format! (
" Routine > start() > (In Tokio Spawn) > {:?} " ,
self_wr_lock . module
) ) ,
Some ( & self_wr_lock . parent_params . msg ) ,
) ;
self_wr_lock . start_time = Some ( chrono ::offset ::Local ::now ( ) ) ;
// Loop iteration
while remainingiter > 1 {
// execution body
self_wr_lock . loopbody ( ) . await ;
// end of loop iteration
remainingiter - = 1 ;
{
self_wr_lock . remaining_iterations = Some ( remainingiter ) ;
self_wr_lock . complete_iterations + = 1 ;
}
}
botlog ::trace (
format! (
" [TRACE][Routine Completed] {} in {} " ,
self_wr_lock . name , self_wr_lock . channel . 0
)
. as_str ( ) ,
Some ( format! (
" Routine > start() > (In Tokio Spawn) > {:?} " ,
self_wr_lock . module
) ) ,
Some ( & self_wr_lock . parent_params . msg ) ,
) ;
} ) )
}
self_wr_lock . join_handle = innerhelper ( self_rw . clone ( ) ) ;
return Ok ( " Successfully Started Routine " . to_string ( ) ) ;
}
2024-03-26 11:29:47 -04:00
Err ( " NOT IMPLEMENTED " . to_string ( ) )
}
2024-03-26 14:30:13 -04:00
async fn loopbody ( & self )
{
( self . exec_body ) (
self . parent_params . clone ( )
) . await ;
}
2024-03-26 11:29:47 -04:00
pub fn stop ( & self ) -> Result < String , String >
{
Err ( " NOT IMPLEMENTED " . to_string ( ) )
}
pub fn restart (
& self ,
_force : bool
) -> Result < String , String >
{
// force flag aborts the routine immediately (like cancel())
Err ( " NOT IMPLEMENTED " . to_string ( ) )
}
pub fn cancel ( & self ) -> Result < String , String >
{
// [ ] Likely calls abort()
// Related :
// https://docs.rs/tokio/latest/tokio/task/struct.JoinHandle.html#method.abort
Err ( " NOT IMPLEMENTED " . to_string ( ) )
}
}
2023-12-21 00:48:09 -05:00
2024-03-22 20:18:02 -04:00
type StatusdbEntry = ( ModGroup , Vec < StatusType > ) ;
2024-03-24 15:46:08 -04:00
type ModuleActions = Vec < Arc < RwLock < BotAction > > > ;
2024-03-22 20:18:02 -04:00
2024-02-25 10:40:54 -05:00
pub struct ModulesManager {
2024-03-22 15:55:56 -04:00
statusdb : Arc < RwLock < HashMap < BotModule , StatusdbEntry > > > ,
2024-03-24 15:46:08 -04:00
pub botactions : Arc < RwLock < HashMap < BotModule , ModuleActions > > > ,
2023-12-21 00:48:09 -05:00
}
2024-02-18 15:23:58 -05:00
/*
statusdb
2024-02-25 10:40:54 -05:00
< HashMap
2024-03-22 15:55:56 -04:00
< BotModule , < - - e . g . , BotModule ( String ::from ( " experiments001 " ) )
2024-02-18 15:23:58 -05:00
Vec < ModStatusType > < - - shows Enabled / Disabled per Status level
2024-02-25 10:40:54 -05:00
botactions
2024-02-18 15:23:58 -05:00
HashMap <
2024-03-22 15:55:56 -04:00
BotModule , < - - e . g . , BotModule ( String ::from ( " experiments001 " ) )
2024-02-18 15:23:58 -05:00
Vec < BotAction > > BotCommand , Listener
* /
2024-02-25 10:40:54 -05:00
impl ModulesManager {
pub async fn init ( ) -> Arc < ModulesManager > {
2024-03-01 23:36:37 -05:00
let mgr = ModulesManager {
2024-03-02 11:55:16 -05:00
statusdb : Arc ::new ( RwLock ::new ( HashMap ::new ( ) ) ) ,
botactions : Arc ::new ( RwLock ::new ( HashMap ::new ( ) ) ) ,
2023-12-21 00:48:09 -05:00
} ;
2024-02-04 14:28:37 -05:00
// :: [x] initialize core modules
2024-03-02 12:21:18 -05:00
botlog ::trace (
2024-02-25 10:40:54 -05:00
" ModulesManager > init() > Adding modules " ,
2024-02-13 10:11:49 -05:00
Some ( " ModulesManager > init() " . to_string ( ) ) ,
2024-02-25 10:40:54 -05:00
None ,
2024-02-13 10:11:49 -05:00
) ;
2023-12-22 09:21:49 -05:00
2024-03-02 11:55:16 -05:00
let mgrarc = Arc ::new ( mgr ) ;
2024-03-02 12:21:18 -05:00
2024-03-02 11:55:16 -05:00
// 1. load core modules
crate ::core ::identity ::init ( Arc ::clone ( & mgrarc ) ) . await ;
2024-03-22 18:49:07 -04:00
crate ::core ::botmodules ::init ( Arc ::clone ( & mgrarc ) ) . await ;
2024-03-02 11:55:16 -05:00
// 2. load custom modules
crate ::custom ::init ( Arc ::clone ( & mgrarc ) ) . await ;
2024-02-25 10:40:54 -05:00
botlog ::trace (
" >> Modules Manager : End of Init " ,
2024-02-13 10:11:49 -05:00
Some ( " ModulesManager > init() " . to_string ( ) ) ,
2024-02-25 10:40:54 -05:00
None ,
2024-02-13 10:11:49 -05:00
) ;
2023-12-21 00:48:09 -05:00
2024-03-02 11:55:16 -05:00
mgrarc
2024-02-25 10:40:54 -05:00
}
2023-12-21 00:48:09 -05:00
2024-03-22 08:21:10 -04:00
2024-03-22 15:55:56 -04:00
pub async fn moduleslist ( & self ) -> HashMap < BotModule , ModGroup >
2024-03-22 08:21:10 -04:00
{
// let db = Arc::clone(&self.statusdb);
let db = self . statusdb . clone ( ) ;
let dblock = db . read ( ) . await ;
let mut outmap = HashMap ::new ( ) ;
for ( k , v ) in & ( * dblock ) {
let ( mgrp , _ ) = v ;
let mtype = k ;
outmap . insert ( ( * mtype ) . clone ( ) , ( * mgrp ) . clone ( ) ) ;
}
outmap
}
2024-03-22 15:55:56 -04:00
pub async fn modstatus ( & self , in_module : BotModule , in_chnl : Channel ) -> StatusType {
2023-12-21 00:48:09 -05:00
// Example usage : botmanager.modstatus(
// BotModule("GambaCore"),
// Channel("modulatingforce")
2024-02-25 10:40:54 -05:00
// )
// - The ModStatusType checks in the context of the given channel ,
2023-12-21 00:48:09 -05:00
// but also validates based on wheher the module is disabled at a bot instance
// level as well
2024-03-21 12:21:00 -04:00
let dbt = self . statusdb . read ( ) . await ;
let ( mgrp , statusvector ) = dbt . get ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
StatusType ::Enabled ( StatusLvl ::Instance ) // This forces core to be validated as Enabled, even if undesired scenario of missing StatusLvl::Instance or empty vectors
} ,
ModGroup ::Custom = > {
/*
[ x ] 1. If Disabled at Instance Level ,
[ x ] a . And Enabled at a Channel Level > return Enabled ( Channel )
[ x ] b . And Disabled at a Channel Level > return Disabled ( Channel )
[ x ] c . And Not Defined at Channel Level > return Disabled ( Instance )
[ x ] 2. If Enabled at Instance Level ,
[ x ] a . And Enabled at a Channel Level > return Enabled ( Channel )
[ x ] b . And Disabled at a Channel Level > return Disabled ( Channel )
[ x ] c . And Not Defined at Channel Level > return Enabled ( Instance )
* /
if statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Instance ) ) {
// [x] 1. If Disabled at Instance Level ,
if statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] a. And Enabled at a Channel Level > return Enabled(Channel)
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else if statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] b. And Disabled at a Channel Level > return Disabled(Channel)
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else {
// [x] c. And Not Defined at Channel Level > return Disabled(Instance)
StatusType ::Disabled ( StatusLvl ::Instance )
}
} else if statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Instance ) ) {
// [x] 2. If Enabled at Instance Level ,
if statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] a. And Enabled at a Channel Level > return Enabled(Channel)
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else if statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] b. And Disabled at a Channel Level > return Disabled(Channel)
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else {
// [x] c. And Not Defined at Channel Level > return Enabled(Instance)
StatusType ::Enabled ( StatusLvl ::Instance )
}
} else {
// ? In some unexpected scenario (e.g., not define at instance level), assume Disabled at Instance level and set as this way
self . set_instance_disabled ( in_module ) . await ;
StatusType ::Disabled ( StatusLvl ::Instance )
}
} ,
}
//StatusType::Enabled(StatusLvl::Instance)
2023-12-21 00:48:09 -05:00
}
2024-03-21 21:20:16 -04:00
pub async fn exec_enable (
& self ,
requestor : String ,
requestor_badge : Option < ChatBadge > ,
2024-03-22 15:55:56 -04:00
trg_module : BotModule ,
2024-03-21 21:20:16 -04:00
trg_level : StatusLvl ,
2024-03-22 17:06:09 -04:00
id : Arc < RwLock < IdentityManager > > ,
2024-03-21 21:20:16 -04:00
) -> ChangeResult
{
/*
1. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
1 a . , and is not - i ( to instance ) , return a Failure recommending BotAdmin promote themselves first
1 b . , and is - i ( to instance ) , return a Success
2. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
2 a . , and is not - i ( to instance ) , return a Success
2 b . , and is - i ( to instance ) , return a Failure they are not allowed
3. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
3. can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster ) & can_user_run for cmdreqRoles including BotAdmin
3 a . , and is not - i ( to instance ) , return a Success
3 b . , and is - i ( to instance ) , return a Success
* /
/*
2024-03-22 21:06:15 -04:00
[ x ] 1. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
2024-03-21 21:20:16 -04:00
1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
1 a . , and is - i ( to instance ) , return a Success
1 b . , and is not - i ( to instance ) , return a Failure recommending BotAdmin promote themselves first
* /
2024-03-22 17:06:09 -04:00
// [x] Validate in trg_module first
let modlist = self . moduleslist ( ) . await ;
let rslt = modlist . get ( & trg_module ) ;
2024-03-22 20:18:02 -04:00
if rslt . is_none ( ) {
2024-03-22 17:06:09 -04:00
return ChangeResult ::Failed ( " Module doesn't exist " . to_string ( ) ) ;
}
2024-03-24 21:50:28 -04:00
botlog ::trace (
" ACQUIRING WRITE LOCK : ID " ,
Some ( " ModulesManager > Exec_enable " . to_string ( ) ) ,
None ,
) ;
2024-03-22 17:06:09 -04:00
2024-03-21 21:20:16 -04:00
let mut idlock = id . write ( ) . await ;
// if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
let arb_chnl = match trg_level . clone ( ) {
2024-03-22 15:55:56 -04:00
StatusLvl ::Instance = > Channel ( requestor . to_lowercase ( ) ) ,
2024-03-21 21:20:16 -04:00
StatusLvl ::Ch ( a ) = > a ,
} ;
2024-03-22 15:55:56 -04:00
const OF_CMD_CHANNEL :Channel = Channel ( String ::new ( ) ) ;
2024-03-21 21:20:16 -04:00
let ( admin_level_access , _ ) = idlock . can_user_run ( requestor . clone ( ) , arb_chnl . clone ( ) , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::BotAdmin ,
] ) . await ;
let ( chnl_elevated_access , _ ) = idlock . can_user_run ( requestor , arb_chnl , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ) . await ;
2024-03-22 17:06:09 -04:00
2024-03-21 21:20:16 -04:00
if let Permissible ::Allow = admin_level_access {
if let Permissible ::Block = chnl_elevated_access {
2024-03-22 17:06:09 -04:00
botlog ::debug (
& format! ( " ?? REACHED INNER TIER :
admin_level_access : { :? } ; chnl_elevated_access : { :? } " ,
admin_level_access , chnl_elevated_access ) ,
Some ( " botmodules.rs > exec_enable() " . to_string ( ) ) ,
None ,
) ;
2024-03-21 21:20:16 -04:00
match trg_level {
StatusLvl ::Instance = > {
self . set_instance_enabled ( trg_module . clone ( ) ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Enabled at Instance Level " . to_string ( ) ) ;
2024-03-21 21:20:16 -04:00
} ,
StatusLvl ::Ch ( _ ) = > {
2024-03-22 17:06:09 -04:00
return ChangeResult ::Failed ( " Promote yourself Temporarily First " . to_string ( ) ) ;
2024-03-21 21:20:16 -04:00
} ,
} ;
2024-03-22 17:06:09 -04:00
2024-03-21 21:20:16 -04:00
}
}
/*
2024-03-22 21:06:15 -04:00
[ x ] 2. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
2024-03-21 21:20:16 -04:00
2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
2 a . , and is - i ( to instance ) , return a Failure they are not allowed
2 b . , and is not - i ( to instance ) , return a Success
* /
if let Permissible ::Block = admin_level_access {
if let Permissible ::Allow = chnl_elevated_access {
match trg_level . clone ( ) {
StatusLvl ::Instance = > {
2024-03-22 17:06:09 -04:00
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
2024-03-21 21:20:16 -04:00
} ,
StatusLvl ::Ch ( in_chnl ) = > {
self . set_ch_enabled ( trg_module . clone ( ) , in_chnl ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) ) ;
2024-03-21 21:20:16 -04:00
} ,
} ;
}
}
/*
2024-03-22 21:06:15 -04:00
[ x ] 3. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
2024-03-21 21:20:16 -04:00
3. can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster ) & can_user_run for cmdreqRoles including BotAdmin
3 a . , and is not - i ( to instance ) , return a Success
3 b . , and is - i ( to instance ) , return a Success
* /
if let Permissible ::Allow = admin_level_access {
if let Permissible ::Allow = chnl_elevated_access {
match trg_level {
StatusLvl ::Instance = > {
self . set_instance_enabled ( trg_module . clone ( ) ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Enabled at Instance Level " . to_string ( ) ) ;
2024-03-21 21:20:16 -04:00
} ,
StatusLvl ::Ch ( in_chnl ) = > {
self . set_ch_enabled ( trg_module . clone ( ) , in_chnl ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) ) ;
2024-03-21 21:20:16 -04:00
} ,
} ;
}
}
2024-03-22 17:06:09 -04:00
// Respond in case of General Chatter
// The below should NOT be required , as current internal logic would prevent
// a BotCommand to be ran by a Chatter if it requires any special roles and
// that chatter does not have htose roles
// However, below is added to satisfy unit tests
if let Permissible ::Block = admin_level_access {
if let Permissible ::Block = chnl_elevated_access {
match trg_level {
StatusLvl ::Instance = > {
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
} ,
StatusLvl ::Ch ( _ ) = > {
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
} ,
} ;
}
}
2024-03-21 21:20:16 -04:00
// =======================
// =======================
// =======================
2024-03-22 17:06:09 -04:00
botlog ::debug (
& format! ( " FAILURE involves :
admin_level_access : { :? } ; chnl_elevated_access : { :? } " ,
admin_level_access , chnl_elevated_access ) ,
Some ( " botmodules.rs > exec_enable() " . to_string ( ) ) ,
None ,
) ;
2024-03-21 21:20:16 -04:00
2024-03-22 17:06:09 -04:00
Log ::flush ( ) ;
2024-03-21 21:20:16 -04:00
2024-03-22 08:21:10 -04:00
ChangeResult ::Failed ( " ERROR : Not implemented yet " . to_string ( ) )
}
pub async fn exec_disable (
& self ,
requestor : String ,
requestor_badge : Option < ChatBadge > ,
2024-03-22 15:55:56 -04:00
trg_module : BotModule ,
2024-03-22 08:21:10 -04:00
trg_level : StatusLvl ,
force : bool ,
2024-03-22 17:06:09 -04:00
id : Arc < RwLock < IdentityManager > > ,
2024-03-22 08:21:10 -04:00
) -> ChangeResult
{
/*
1. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
1 a . , and has no special flags ( - i / - f ) , return a Failure recommending BotAdmin promote themselves first
1 b . , and is - i ( to instance ) , return a Success
1 c . , and is - f ( forced ) , return a Success
2. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
2 a . , and has no special flags ( - i / - f ) , return a Success
2 b . , and is - i ( to instance ) , return a Failure they are not allowed
2 c . , and is - f ( forced ) , return a Failure they are not allowed
3. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
3. can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster ) & can_user_run for cmdreqRoles including BotAdmin
3 a . , and has no special flags ( - i / - f ) , return a Success
3 b . , and is - i ( to instance ) , return a Success
3 c . , and is - f ( forced ) , return a Success
* /
2024-03-22 17:06:09 -04:00
// [x] Validate in trg_module first
let modlist = self . moduleslist ( ) . await ;
let rslt = modlist . get ( & trg_module ) ;
2024-03-22 20:18:02 -04:00
if rslt . is_none ( ) {
2024-03-22 17:06:09 -04:00
return ChangeResult ::Failed ( " Module doesn't exist " . to_string ( ) ) ;
}
2024-03-24 21:50:28 -04:00
botlog ::trace (
" ACQUIRING WRITE LOCK : ID " ,
Some ( " ModulesManager > Exec_disable " . to_string ( ) ) ,
None ,
) ;
2024-03-22 08:21:10 -04:00
let mut idlock = id . write ( ) . await ;
// if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
let arb_chnl = match trg_level . clone ( ) {
2024-03-22 15:55:56 -04:00
StatusLvl ::Instance = > Channel ( requestor . to_lowercase ( ) ) ,
2024-03-22 08:21:10 -04:00
StatusLvl ::Ch ( a ) = > a ,
} ;
2024-03-22 15:55:56 -04:00
const OF_CMD_CHANNEL :Channel = Channel ( String ::new ( ) ) ;
2024-03-22 08:21:10 -04:00
let ( admin_level_access , _ ) = idlock . can_user_run ( requestor . clone ( ) , arb_chnl . clone ( ) , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::BotAdmin ,
] ) . await ;
let ( chnl_elevated_access , _ ) = idlock . can_user_run ( requestor , arb_chnl , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ) . await ;
/*
2024-03-22 21:06:15 -04:00
[ x ] 1. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
2024-03-22 08:21:10 -04:00
1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
1 a . , and is - f ( forced ) , return a Success
1 b . , and is - i ( to instance ) , return a Success
1 c . , and has no special flags ( - i / - f ) , return a Failure recommending BotAdmin promote themselves first
* /
if let Permissible ::Allow = admin_level_access {
if let Permissible ::Block = chnl_elevated_access {
if force {
self . force_disable ( trg_module . clone ( ) ) . await ;
return ChangeResult ::Success ( " Forced Disable " . to_string ( ) ) ;
} else {
match trg_level {
StatusLvl ::Instance = > {
self . set_instance_disabled ( trg_module . clone ( ) ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Disabled at Instance Level " . to_string ( ) ) ;
2024-03-22 08:21:10 -04:00
} ,
StatusLvl ::Ch ( _ ) = > {
2024-03-22 17:06:09 -04:00
return ChangeResult ::Failed ( " Promote yourself Temporarily First " . to_string ( ) ) ;
2024-03-22 08:21:10 -04:00
} ,
} ;
}
}
}
/*
2024-03-22 21:06:15 -04:00
[ x ] 2. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
2 a . , and is - f ( forced ) , return a Failure they are not allowed
2 b . , and is - i ( to instance ) , return a Failure they are not allowed
2 c . , and has no special flags ( - i / - f ) , return a Success
2024-03-22 08:21:10 -04:00
* /
if let Permissible ::Block = admin_level_access {
if let Permissible ::Allow = chnl_elevated_access {
if force {
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
} else {
match trg_level . clone ( ) {
StatusLvl ::Instance = > {
2024-03-22 17:06:09 -04:00
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
2024-03-22 08:21:10 -04:00
} ,
StatusLvl ::Ch ( in_chnl ) = > {
self . set_ch_disabled ( trg_module . clone ( ) , in_chnl ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Disabled at Channel Level " . to_string ( ) ) ;
2024-03-22 08:21:10 -04:00
} ,
} ;
}
}
}
/*
2024-03-22 21:06:15 -04:00
[ x ] 3. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
3. can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster ) & can_user_run for cmdreqRoles including BotAdmin
3 a . , and is - f ( forced ) , return a Success
3 b . , and is - i ( to instance ) , return a Success
3 c . , and has no special flags ( - i / - f ) , return a Success
2024-03-22 08:21:10 -04:00
* /
if let Permissible ::Allow = admin_level_access {
if let Permissible ::Allow = chnl_elevated_access {
if force {
self . force_disable ( trg_module . clone ( ) ) . await ;
return ChangeResult ::Success ( " Forced Disable " . to_string ( ) ) ;
} else {
match trg_level {
StatusLvl ::Instance = > {
self . set_instance_disabled ( trg_module . clone ( ) ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Disabled at Instance Level " . to_string ( ) ) ;
2024-03-22 08:21:10 -04:00
} ,
StatusLvl ::Ch ( in_chnl ) = > {
self . set_ch_disabled ( trg_module . clone ( ) , in_chnl ) . await ;
2024-03-22 17:06:09 -04:00
return ChangeResult ::Success ( " Disabled at Channel Level " . to_string ( ) ) ;
2024-03-22 08:21:10 -04:00
} ,
} ;
}
}
}
2024-03-22 17:06:09 -04:00
// Respond in case of General Chatter
// The below should NOT be required , as current internal logic would prevent
// a BotCommand to be ran by a Chatter if it requires any special roles and
// that chatter does not have htose roles
// However, below is added to satisfy unit tests
if let Permissible ::Block = admin_level_access {
if let Permissible ::Block = chnl_elevated_access {
match trg_level {
StatusLvl ::Instance = > {
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
} ,
StatusLvl ::Ch ( _ ) = > {
return ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ;
} ,
} ;
}
}
2024-03-22 08:21:10 -04:00
ChangeResult ::Failed ( " ERROR : Not implemented yet " . to_string ( ) )
2024-03-21 21:20:16 -04:00
}
2024-03-22 15:55:56 -04:00
pub async fn set_instance_disabled ( & self , in_module : BotModule ) -> ( StatusType , ChangeResult ) {
2024-03-21 00:05:52 -04:00
// at Instance level
// - If core module, do nothing
2024-03-21 02:13:23 -04:00
let mut dbt = self . statusdb . write ( ) . await ;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Failed ( " Core Modules cannot be disabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all instance level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x | ( * x = = StatusType ::Enabled ( StatusLvl ::Instance ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Instance ) ) ) {
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
(
StatusType ::Disabled ( StatusLvl ::Instance ) ,
2024-03-21 12:21:00 -04:00
ChangeResult ::Success ( " Set Disabled at Instance " . to_string ( ) )
2024-03-21 02:13:23 -04:00
)
} ,
}
2023-12-21 00:48:09 -05:00
}
2024-03-22 15:55:56 -04:00
pub async fn force_disable ( & self , in_module : BotModule ) -> ( StatusType , ChangeResult ) {
2024-03-21 02:13:23 -04:00
// Disables the module at Instance level, and removes all Enabled at Channel level
2024-03-21 00:05:52 -04:00
// - Bot Moderators MUST Re-enable if they were enabled before
// - If core module, do nothing
2024-03-21 02:13:23 -04:00
let mut dbt = self . statusdb . write ( ) . await ;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Failed ( " Core Modules cannot be disabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all instance level pattern & Enabled Channel patterns for the module
// Disabled at Channel level might be fine? That way if it gets Enabled at instance level, channel level disables are uninterrupted
while let Some ( index ) = statusvector
. iter ( )
. position ( | x |
if ( * x = = StatusType ::Enabled ( StatusLvl ::Instance ) )
| | ( * x = = StatusType ::Disabled ( StatusLvl ::Instance ) ) {
true
2024-03-22 20:18:02 -04:00
} else {
matches! ( ( * x ) . clone ( ) , StatusType ::Enabled ( StatusLvl ::Ch ( _ ) ) )
}
2024-03-21 02:13:23 -04:00
)
{
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
(
StatusType ::Disabled ( StatusLvl ::Instance ) ,
2024-03-21 09:37:08 -04:00
ChangeResult ::Success ( " Forced Disabled " . to_string ( ) )
2024-03-21 02:13:23 -04:00
)
} ,
}
2023-12-21 00:48:09 -05:00
}
2024-03-22 15:55:56 -04:00
pub async fn set_instance_enabled ( & self , in_module : BotModule ) -> ( StatusType , ChangeResult ) {
2024-03-21 00:05:52 -04:00
// at Instance level
// - If core module, do nothing
2024-03-21 12:21:00 -04:00
let mut dbt = self . statusdb . write ( ) . await ;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::NoChange ( " Core Modules are always Enabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all instance level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x | ( * x = = StatusType ::Enabled ( StatusLvl ::Instance ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Instance ) ) ) {
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Success ( " Set Enabled at Instance " . to_string ( ) )
)
} ,
}
2024-03-21 00:05:52 -04:00
}
2024-03-22 15:55:56 -04:00
pub async fn set_ch_disabled ( & self , in_module : BotModule , in_chnl : Channel ) -> ( StatusType , ChangeResult ) {
2024-03-21 00:05:52 -04:00
// at Instance level
// - If core module, do nothing
2024-03-21 12:21:00 -04:00
let mut dbt = self . statusdb . write ( ) . await ;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Failed ( " Core Modules cannot be disabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all channel level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x |
( * x = = StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) )
{
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) ;
(
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ,
ChangeResult ::Success ( " Set Disabled at Channel Level " . to_string ( ) )
)
} ,
}
2024-03-21 00:05:52 -04:00
}
2024-03-22 15:55:56 -04:00
pub async fn set_ch_enabled ( & self , in_module : BotModule , in_chnl : Channel ) -> ( StatusType , ChangeResult ) {
2024-03-21 00:05:52 -04:00
// at Instance level
// - If core module, do nothing
2024-03-21 12:21:00 -04:00
let mut dbt = self . statusdb . write ( ) . await ;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::NoChange ( " Core Modules are always Enabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all channel level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x |
( * x = = StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) )
{
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) ;
(
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ,
ChangeResult ::Success ( " Set Enabled at Channel Level " . to_string ( ) )
)
} ,
}
2024-03-21 00:05:52 -04:00
}
2024-03-22 15:55:56 -04:00
pub async fn add_botaction ( & self , in_module : BotModule , in_action : BotAction ) {
2024-03-20 23:20:46 -04:00
self . int_add_botaction ( in_module , ModGroup ::Custom , in_action ) . await ;
}
2024-03-22 15:55:56 -04:00
pub async fn add_core_act ( & self , in_module : BotModule , in_action : BotAction ) {
2024-03-20 23:20:46 -04:00
self . int_add_botaction ( in_module , ModGroup ::Core , in_action ) . await ;
}
2024-03-21 02:13:23 -04:00
2024-03-22 15:55:56 -04:00
pub async fn affirm_in_statusdb ( & self , in_module :BotModule , in_modgroup : ModGroup ) {
2024-03-21 02:13:23 -04:00
let mut dbt = self . statusdb . write ( ) . await ;
let ( _ , statusvector ) = dbt . entry ( in_module . clone ( ) ) . or_insert ( ( in_modgroup . clone ( ) , Vec ::new ( ) ) ) ;
if ! statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Instance ) ) & & ! statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Instance ) )
{
match in_modgroup {
ModGroup ::Core = > statusvector . push ( StatusType ::Enabled ( StatusLvl ::Instance ) ) , // Pushes the Module as Enabled at Instance Level
ModGroup ::Custom = > statusvector . push ( StatusType ::Disabled ( StatusLvl ::Instance ) ) ,
}
}
}
2024-03-22 15:55:56 -04:00
async fn int_add_botaction ( & self , in_module : BotModule , in_modgroup : ModGroup , in_action : BotAction ) {
2024-02-25 10:40:54 -05:00
botlog ::trace (
" Add botaction called " ,
Some ( " ModulesManager > init() " . to_string ( ) ) ,
None ,
2024-02-13 10:11:49 -05:00
) ;
2023-12-21 20:11:32 -05:00
/*
adds a BotAction to the Modules Manager - This will require a BotModule passed as well
This will including the logic of a valid add
If it fails to add , either a PANIC or some default coded business rules that handles the botaction add
For example , this Should PANIC ( ideally Panic ? ) if it does not successfully add a bot module
- - Being unable to indicates a Programming / Developer code logic issue : They cannot add botactions that already exists ( ? )
- - In particular to BotCommands , which must have Unique command call names and aliases that to not conflict with any other
already BotCommand added name or alias
Other types might be fine ? For example , if 2 modules have their own listeners but each have the name " targetchatter " ,
2024-02-25 10:40:54 -05:00
both would be called separately , even if they both have the same or different logic
2023-12-21 20:11:32 -05:00
* /
2024-02-25 10:40:54 -05:00
// [x] Before Adding, validate the following :
// - If BotAction to Add is a BotCommand , In Module Manager DB (botactions),
2023-12-21 20:11:32 -05:00
// Check All Other BotAction Command Names & Aliases to ensure they don't conflict
2024-03-22 15:55:56 -04:00
async fn find_conflict_module ( mgr : & ModulesManager , act : & BotAction ) -> Option < BotModule > {
2024-03-24 15:46:08 -04:00
2024-01-29 04:28:58 -05:00
if let BotAction ::C ( incmd ) = act {
2024-03-02 11:55:16 -05:00
let actdb = mgr . botactions . read ( ) . await ;
2024-03-02 12:21:18 -05:00
2024-03-02 11:55:16 -05:00
for ( module , moduleactions ) in & ( * actdb ) {
2024-03-24 15:46:08 -04:00
// for modact in moduleactions.iter() {
for modact_prelock in moduleactions . iter ( ) {
let modact = modact_prelock . read ( ) . await ;
// if let BotAction::C(dbcmd) = &modact {
if let BotAction ::C ( dbcmd ) = & ( * modact ) {
2024-01-29 04:28:58 -05:00
// At this point, there is an command incmd and looked up dbcmd
2023-12-21 20:11:32 -05:00
2024-01-29 04:28:58 -05:00
// [x] check if given botcommand c.command:String conflicts with any in botactions
2023-12-21 20:11:32 -05:00
2024-01-29 04:28:58 -05:00
if incmd . command . to_lowercase ( ) = = dbcmd . command . to_lowercase ( ) {
// Returning State - with the identified module
return Some ( module . clone ( ) ) ; // works
2024-02-25 10:40:54 -05:00
}
2023-12-21 20:11:32 -05:00
2024-01-29 04:28:58 -05:00
for a in & dbcmd . alias {
if incmd . command . to_lowercase ( ) = = a . to_lowercase ( ) {
// Returning State - with the identified module
2024-03-02 12:21:18 -05:00
2024-01-29 04:28:58 -05:00
return Some ( module . clone ( ) ) ; // works
2024-02-25 10:40:54 -05:00
}
}
2023-12-21 20:11:32 -05:00
2024-01-29 04:28:58 -05:00
// [x] Then do the same check except for each c.alias
2023-12-21 20:11:32 -05:00
2024-01-29 04:28:58 -05:00
for inalias in & incmd . alias {
if inalias . to_lowercase ( ) = = dbcmd . command . to_lowercase ( ) {
// Returning State - with the identified module
2024-03-02 12:21:18 -05:00
2024-01-29 04:28:58 -05:00
return Some ( module . clone ( ) ) ; // works
2024-02-25 10:40:54 -05:00
}
2023-12-21 20:11:32 -05:00
2024-01-29 04:28:58 -05:00
for a in & dbcmd . alias {
if inalias . to_lowercase ( ) = = a . to_lowercase ( ) {
// Returning State - with the identified module
2024-03-02 12:21:18 -05:00
2024-01-29 04:28:58 -05:00
return Some ( module . clone ( ) ) ; // works
2024-02-25 10:40:54 -05:00
}
}
2024-01-29 04:28:58 -05:00
}
}
}
}
}
2023-12-21 20:11:32 -05:00
// for all other scenarios (e.g., Listener, Routine), find no conflicts
None
}
2024-03-01 23:36:37 -05:00
if let Some ( c ) = find_conflict_module ( self , & in_action ) . await {
panic! (
2024-02-25 10:40:54 -05:00
" ERROR: Could not add module; there was a conflict with existing module {:?} " ,
c
2024-03-01 23:36:37 -05:00
)
2023-12-21 20:11:32 -05:00
}
2024-03-21 02:13:23 -04:00
self . affirm_in_statusdb ( in_module . clone ( ) , in_modgroup ) . await ;
2024-02-12 01:25:12 -05:00
let mut a = self . botactions . write ( ) . await ;
2024-03-02 12:21:18 -05:00
let modactions = a . entry ( in_module . clone ( ) ) . or_insert ( Vec ::new ( ) ) ;
2023-12-21 17:22:40 -05:00
2024-03-24 15:46:08 -04:00
modactions . push ( Arc ::new ( RwLock ::new ( in_action ) ) ) ;
2023-12-21 17:22:40 -05:00
2024-02-25 10:40:54 -05:00
botlog ::trace (
2024-03-02 12:21:18 -05:00
format! (
" Modules Manager> add_botaction called - botactions size : {} " ,
modactions . len ( )
)
. as_str ( ) ,
2024-02-25 10:40:54 -05:00
Some ( " ModulesManager > init() " . to_string ( ) ) ,
None ,
2024-02-13 10:11:49 -05:00
) ;
2023-12-21 17:22:40 -05:00
}
2024-03-22 15:55:56 -04:00
fn _statuscleanup ( & self , _ : Option < Channel > ) {
2024-02-25 10:40:54 -05:00
// internal cleans up statusdb . For example :
2023-12-21 12:10:50 -05:00
// - remove redudancies . If we see several Enabled("m"), only keep 1x
// - Clarify Conflict. If we see Enabled("m") and Disabled("m") , we remove Enabled("m") and keep Disabled("m")
// the IDEAL is that this is ran before every read/update operation to ensure quality
2024-03-22 15:55:56 -04:00
// Option<Channel> can pass Some(Channel("m")) (as an example) so statuscleanup only works on the given channel
2023-12-21 12:10:50 -05:00
// Passing None to chnl may be a heavy operation, as this will review and look at the whole table
}
2024-02-25 10:40:54 -05:00
}
2024-03-21 14:01:54 -04:00
// =====================
// =====================
// =====================
// =====================
// =====================
#[ cfg(test) ]
mod core_modulesmanager {
use casual_logger ::Log ;
use casual_logger ::Extension ;
use super ::* ;
2024-03-22 08:21:10 -04:00
#[ test ]
2024-03-22 08:40:09 -04:00
fn case_insensitive_test ( ) {
2024-03-22 08:21:10 -04:00
Log ::set_file_ext ( Extension ::Log ) ;
assert_eq! (
2024-03-22 17:06:09 -04:00
BotModule ( " TEST " . to_string ( ) ) ,
BotModule ( " test " . to_string ( ) )
2024-03-22 08:21:10 -04:00
) ;
}
2024-03-21 14:01:54 -04:00
/*
Possible Tests
[ x ] Test 1 - Custom ModGroup Workflow
1. affirm_in_statusdb ( Experiments01 , Custom )
2. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
3. set_instance_enabled ( Experiments01 )
4. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
5. set_ch_disabled ( Experiments01 , TestChannel01 )
6. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
7. set_ch_enabled ( Experiments01 , TestChannel01 ) & set_ch_disabled ( Experiments01 , TestChannel02 )
8. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
9. set_instance_disabled ( Experiments01 )
10. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
11. force_disable ( Experiments01 )
12. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
[ x ] Test 2 - Core ModGroup Workflow
1. affirm_in_statusdb ( CoreModule01 , Core )
2. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
3. set_instance_enabled ( CoreModule01 )
4. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
5. set_ch_disabled ( CoreModule01 , TestChannel01 )
6. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
7. set_ch_enabled ( CoreModule01 , TestChannel01 ) & set_ch_disabled ( CoreModule01 , TestChannel02 )
8. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
9. set_instance_disabled ( CoreModule01 )
10. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
11. force_disable ( CoreModule01 )
12. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
* /
async fn complex_workflow (
2024-03-22 15:55:56 -04:00
in_module : BotModule ,
2024-03-21 14:01:54 -04:00
in_modgroup : ModGroup ,
2024-03-22 15:55:56 -04:00
in_chnl1 : Channel ,
in_chnl2 : Channel )
2024-03-21 14:01:54 -04:00
{
let mgr = ModulesManager ::init ( ) . await ;
/*
1. affirm_in_statusdb ( Experiments01 , Custom )
2. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . affirm_in_statusdb ( in_module . clone ( ) , in_modgroup . clone ( ) ) . await ;
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
3. set_instance_enabled ( Experiments01 )
4. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_instance_enabled ( in_module . clone ( ) ) . await ;
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
5. set_ch_disabled ( Experiments01 , TestChannel01 )
6. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_ch_disabled ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ;
//StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl1 . clone ( ) ) ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
7. set_ch_enabled ( Experiments01 , TestChannel01 ) & set_ch_disabled ( Experiments01 , TestChannel02 )
8. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_ch_enabled ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ;
//StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl1 . clone ( ) ) ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
9. set_instance_disabled ( Experiments01 )
10. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_instance_disabled ( in_module . clone ( ) ) . await ;
// StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl1 . clone ( ) ) ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
11. force_disable ( Experiments01 )
12. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . force_disable ( in_module . clone ( ) ) . await ;
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
}
#[ tokio::test ]
async fn custom_modgroup_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
/*
[ x ] Test 1 - Custom ModGroup Workflow
1. affirm_in_statusdb ( Experiments01 , Custom )
2. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
3. set_instance_enabled ( Experiments01 )
4. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
5. set_ch_disabled ( Experiments01 , TestChannel01 )
6. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
7. set_ch_enabled ( Experiments01 , TestChannel01 ) & set_ch_disabled ( Experiments01 , TestChannel02 )
8. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
9. set_instance_disabled ( Experiments01 )
10. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
11. force_disable ( Experiments01 )
12. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
let in_module = BotModule ( " Experiments01 " . to_string ( ) ) ;
let in_modgroup = ModGroup ::Custom ;
let ( in_chnl1 , in_chnl2 ) =
2024-03-22 15:55:56 -04:00
( Channel ( " TestChannel01 " . to_string ( ) ) , Channel ( " TestChannel02 " . to_string ( ) ) ) ;
2024-03-21 14:01:54 -04:00
complex_workflow ( in_module , in_modgroup , in_chnl1 , in_chnl2 ) . await ;
}
#[ tokio::test ]
async fn core_modgroup_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
let in_module = BotModule ( " CoreModule01 " . to_string ( ) ) ;
let in_modgroup = ModGroup ::Core ;
let ( in_chnl1 , in_chnl2 ) =
2024-03-22 15:55:56 -04:00
( Channel ( " TestChannel01 " . to_string ( ) ) , Channel ( " TestChannel02 " . to_string ( ) ) ) ;
2024-03-21 14:01:54 -04:00
complex_workflow ( in_module , in_modgroup , in_chnl1 , in_chnl2 ) . await ;
}
2024-03-22 17:06:09 -04:00
/*
1. Create new ModulesManager & Identity Manager
2. modmgr . affirm_in_statusdb ( Experiments01 , Custom )
3. affirm when BotAdmin attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
4. affirm when BotAdmin attempts to exec_disable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
d . force disable
1. Create new ModulesManager & Identity Manager
2. modmgr . affirm_in_statusdb ( Experiments01 , Custom )
3. affirm when Mod attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
4. affirm when Mod attempts to exec_disable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
d . force disable
* /
async fn inner_enable_disable_complex (
requestor :String ,
2024-03-22 15:55:56 -04:00
channel :Channel ,
2024-03-22 17:06:09 -04:00
idmgr :IdentityManager ,
modsmgr :Arc < ModulesManager > )
{
/*
Parent Tests would involve :
- Testing with a BotAdmin User
- Testing with a Mod User
- Testing with a Regular Chatter
* /
enum TestScenarios {
BotadminUser ,
ModUser ,
RegularChatter ,
// ModuleDoesNotExist, // preferring instead to handle in it's own smaller test
}
let mut idlock = idmgr . clone ( ) ;
let requestor_badge = None ; // If they are a Mod on the Given Channel already, that can be evaluated without the current badge
2024-03-22 15:55:56 -04:00
const OF_CMD_CHANNEL :Channel = Channel ( String ::new ( ) ) ;
2024-03-22 17:06:09 -04:00
let ( admin_level_access , _ ) = idlock . can_user_run ( requestor . clone ( ) , channel . clone ( ) , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::BotAdmin ,
] ) . await ;
let ( chnl_elevated_access , _ ) = idlock . can_user_run ( requestor . clone ( ) , channel . clone ( ) , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ) . await ;
let current_test_scenario =
match admin_level_access {
Permissible ::Allow = > {
match chnl_elevated_access {
Permissible ::Allow = > { TestScenarios ::BotadminUser } ,
Permissible ::Block = > { TestScenarios ::BotadminUser }
}
} ,
Permissible ::Block = > {
match chnl_elevated_access {
Permissible ::Allow = > { TestScenarios ::ModUser } ,
Permissible ::Block = > { TestScenarios ::RegularChatter }
}
}
} ;
// [x] 2. modmgr.affirm_in_statusdb(Experiments01,Custom)
let in_module = BotModule ( " Experiments01 " . to_string ( ) ) ;
let in_modgroup = ModGroup ::Custom ;
modsmgr . affirm_in_statusdb ( in_module . clone ( ) , in_modgroup . clone ( ) ) . await ;
/*
[ x ] 3. affirm when BotAdmin attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
* /
// [-] requestor_badge: Option<ChatBadge>,
2024-03-22 15:55:56 -04:00
// [x] trg_module: BotModule,
2024-03-22 17:06:09 -04:00
let trg_module = in_module ;
// [x] trg_level: StatusLvl,
let trg_level = StatusLvl ::Ch ( channel . clone ( ) ) ; // setting to Channel Level
// [x] id: Arc<RwLock<IdentityManager>>,
let id = Arc ::new ( RwLock ::new ( idmgr . clone ( ) ) ) ;
let rslt = modsmgr . exec_enable ( requestor . clone ( ) ,
None ,
trg_module . clone ( ) ,
trg_level . clone ( ) ,
id . clone ( ) ) . await ;
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Failed ( " Promote yourself Temporarily First " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
/*
[ x ] 3. affirm when BotAdmin attempts to exec_enable on the following
b . Channel Level , when they are a Mod
* /
// [x] requestor_badge: Option<ChatBadge>,
2024-03-22 21:06:15 -04:00
2024-03-22 17:06:09 -04:00
let requestor_badge = match current_test_scenario {
TestScenarios ::BotadminUser = >
Some ( ChatBadge ::Mod ) , // setting badge to Mod -- for the Problem Scenario . They are both BotAdmin & Mod
TestScenarios ::ModUser = >
Some ( ChatBadge ::Mod ) , // setting badge to Mod
TestScenarios ::RegularChatter = >
None , // setting badge to None
} ;
let rslt = modsmgr . exec_enable ( requestor . clone ( ) ,
requestor_badge ,
trg_module . clone ( ) ,
trg_level . clone ( ) ,
id . clone ( ) ) . await ;
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
/*
[ x ] 3. affirm when BotAdmin attempts to exec_enable on the following
c . Instance Level
* /
let trg_level = StatusLvl ::Instance ; // setting to Instance level
let requestor_badge = match current_test_scenario {
TestScenarios ::BotadminUser = >
None ,
TestScenarios ::ModUser = >
Some ( ChatBadge ::Mod ) ,
TestScenarios ::RegularChatter = >
None , // setting badge to None
} ;
let rslt = modsmgr . exec_enable ( requestor . clone ( ) ,
requestor_badge , // passing based on scenario
trg_module . clone ( ) ,
trg_level . clone ( ) ,
id . clone ( ) ) . await ;
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Enabled at Instance Level " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
/*
[ x ] 4. affirm when BotAdmin attempts to exec_disable on the following
a . Channel Level , where they are not a Mod
* /
let trg_level = StatusLvl ::Ch ( channel . clone ( ) ) ; // setting to Channel Level
let rslt : ChangeResult = modsmgr . exec_disable ( requestor . clone ( ) ,
None , // Does not have a ChatBadge like Mod
trg_module . clone ( ) ,
trg_level . clone ( ) ,
false ,
id . clone ( ) ) . await ;
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Disabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Disabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
/*
[ x ] 4. affirm when BotAdmin attempts to exec_disable on the following
b . Channel Level , when they are a Mod
* /
let trg_level = StatusLvl ::Ch ( channel . clone ( ) ) ; // setting to Channel Level
2024-03-22 21:06:15 -04:00
2024-03-22 17:06:09 -04:00
let requestor_badge = match current_test_scenario {
TestScenarios ::BotadminUser = >
None ,
TestScenarios ::ModUser = >
Some ( ChatBadge ::Mod ) ,
TestScenarios ::RegularChatter = >
None , // setting badge to None
} ;
let rslt : ChangeResult = modsmgr . exec_disable ( requestor . clone ( ) ,
requestor_badge ,
trg_module . clone ( ) ,
trg_level . clone ( ) ,
false ,
id . clone ( ) ) . await ;
2024-03-22 21:06:15 -04:00
2024-03-22 17:06:09 -04:00
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Disabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Disabled at Channel Level " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
/*
[ x ] 4. affirm when BotAdmin attempts to exec_disable on the following
c . Instance Level
* /
let trg_level = StatusLvl ::Instance ; // setting to Instance level
2024-03-22 21:06:15 -04:00
2024-03-22 17:06:09 -04:00
let rslt : ChangeResult = modsmgr . exec_disable ( requestor . clone ( ) ,
None , // Does not have a ChatBadge like Mod
trg_module . clone ( ) ,
trg_level . clone ( ) ,
false ,
id . clone ( ) ) . await ;
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Disabled at Instance Level " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
/*
[ ] 4. affirm when BotAdmin attempts to exec_disable on the following
d . force disable
* /
let trg_level = StatusLvl ::Instance ; // setting to Instance level
let rslt : ChangeResult = modsmgr . exec_disable ( requestor . clone ( ) ,
None , // Does not have a ChatBadge like Mod
trg_module . clone ( ) ,
trg_level . clone ( ) ,
true , // force flag - true
id . clone ( ) ) . await ;
match current_test_scenario {
TestScenarios ::BotadminUser = >
assert_eq! ( rslt , ChangeResult ::Success ( " Forced Disable " . to_string ( ) ) ) ,
TestScenarios ::ModUser = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
TestScenarios ::RegularChatter = >
assert_eq! ( rslt , ChangeResult ::Failed ( " You're not allowed " . to_string ( ) ) ) ,
}
}
#[ tokio::test ]
async fn enable_disable_bot_admin_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
/*
1. Create new ModulesManager & Identity Manager
2. modmgr . affirm_in_statusdb ( Experiments01 , Custom )
3. affirm when BotAdmin attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
4. affirm when BotAdmin attempts to exec_disable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
d . force disable
* /
// [x] 1. Create new ModulesManager & Identity Manager
let idmgr = IdentityManager ::init ( ) ;
let modsmgr = ModulesManager ::init ( ) . await ;
/*
[ x ] 3. affirm when BotAdmin attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
* /
// [x] Create BotAdmin first
let requestor = " botadministrator " . to_string ( ) ;
idmgr . affirm_chatter_in_db ( requestor . clone ( ) ) . await ;
idmgr
. add_role ( requestor . clone ( ) , identity ::UserRole ::BotAdmin )
. await ;
let rslt = idmgr
. getspecialuserroles ( requestor . clone ( ) , None )
. await ;
assert! ( rslt . contains ( & identity ::UserRole ::BotAdmin ) ) ;
2024-03-22 15:55:56 -04:00
let channel = Channel ( " somechannel " . to_string ( ) ) ;
2024-03-22 17:06:09 -04:00
inner_enable_disable_complex ( requestor , channel , idmgr , modsmgr ) . await ;
}
#[ tokio::test ]
async fn enable_disable_mod_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
/*
1. Create new ModulesManager & Identity Manager
2. modmgr . affirm_in_statusdb ( Experiments01 , Custom )
3. affirm when Mod attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
4. affirm when Mod attempts to exec_disable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
d . force disable
* /
// [x] 1. Create new ModulesManager & Identity Manager
let idmgr = IdentityManager ::init ( ) ;
let modsmgr = ModulesManager ::init ( ) . await ;
let requestor = " mod_user " . to_string ( ) ;
// let botadmin_badge = &None;
2024-03-22 15:55:56 -04:00
let channel = Channel ( " somechannel " . to_string ( ) ) ;
2024-03-22 17:06:09 -04:00
idmgr . affirm_chatter_in_db ( requestor . clone ( ) ) . await ;
idmgr
. add_role ( requestor . clone ( ) , identity ::UserRole ::Mod ( channel . clone ( ) ) )
. await ;
let rslt = idmgr
. getspecialuserroles (
requestor . clone ( ) ,
Some ( channel . clone ( ) ) // None if BotAdmin ; Otherwise, pass Some(Channel)
)
. await ;
assert! ( rslt . contains ( & identity ::UserRole ::Mod ( channel . clone ( ) ) ) ) ;
inner_enable_disable_complex ( requestor , channel , idmgr , modsmgr ) . await ;
}
#[ tokio::test ]
async fn enable_disable_chatter_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
/*
1. Create new ModulesManager & Identity Manager
2. modmgr . affirm_in_statusdb ( Experiments01 , Custom )
3. affirm when Mod attempts to exec_enable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
4. affirm when Mod attempts to exec_disable on the following
a . Channel Level , where they are not a Mod
b . Channel Level , when they are a Mod
c . Instance Level
d . force disable
* /
// [x] 1. Create new ModulesManager & Identity Manager
let idmgr = IdentityManager ::init ( ) ;
let modsmgr = ModulesManager ::init ( ) . await ;
let requestor = " regular_user " . to_string ( ) ;
2024-03-22 15:55:56 -04:00
let channel = Channel ( " somechannel " . to_string ( ) ) ;
2024-03-22 17:06:09 -04:00
idmgr . affirm_chatter_in_db ( requestor . clone ( ) ) . await ;
2024-03-22 21:06:15 -04:00
2024-03-22 17:06:09 -04:00
let rslt = idmgr
. getspecialuserroles (
requestor . clone ( ) ,
Some ( channel . clone ( ) ) // None if BotAdmin ; Otherwise, pass Some(Channel)
)
. await ;
assert! ( ! rslt . contains ( & identity ::UserRole ::Mod ( channel . clone ( ) ) ) | |
! rslt . contains ( & identity ::UserRole ::BotAdmin ) ) ;
inner_enable_disable_complex ( requestor , channel , idmgr , modsmgr ) . await ;
}
#[ tokio::test ]
async fn enable_disable_modulenotexist_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
// [x] 1. Create new ModulesManager & Identity Manager
let idmgr = IdentityManager ::init ( ) ;
let modsmgr = ModulesManager ::init ( ) . await ;
let requestor = " regular_user " . to_string ( ) ;
2024-03-22 21:06:15 -04:00
2024-03-22 15:55:56 -04:00
let channel = Channel ( " somechannel " . to_string ( ) ) ;
2024-03-22 17:06:09 -04:00
idmgr . affirm_chatter_in_db ( requestor . clone ( ) ) . await ;
2024-03-22 21:06:15 -04:00
2024-03-22 17:06:09 -04:00
let rslt = idmgr
. getspecialuserroles (
requestor . clone ( ) ,
Some ( channel . clone ( ) ) // None if BotAdmin ; Otherwise, pass Some(Channel)
)
. await ;
assert! ( ! rslt . contains ( & identity ::UserRole ::Mod ( channel . clone ( ) ) ) | |
! rslt . contains ( & identity ::UserRole ::BotAdmin ) ) ;
// After above, regular chatter is created
// [x] 2. modmgr.affirm_in_statusdb(Existing_Module,Custom)
let in_module = BotModule ( " Existing_Module " . to_string ( ) ) ;
let in_modgroup = ModGroup ::Custom ;
modsmgr . affirm_in_statusdb ( in_module . clone ( ) , in_modgroup . clone ( ) ) . await ;
let trg_level = StatusLvl ::Ch ( channel . clone ( ) ) ; // setting to Channel Level
// [x] Test with Non Existing module > exec
let trg_module = BotModule ( " Non_Existent_Module " . to_string ( ) ) ;
let rslt = modsmgr . exec_enable ( requestor . clone ( ) ,
None ,
trg_module . clone ( ) ,
trg_level . clone ( ) ,
Arc ::new ( RwLock ::new ( idmgr . clone ( ) ) ) ) . await ;
assert_eq! ( rslt , ChangeResult ::Failed ( " Module doesn't exist " . to_string ( ) ) ) ;
2024-03-22 21:06:15 -04:00
// [x] Test with Non Existing module > disable
2024-03-22 17:06:09 -04:00
let trg_module = BotModule ( " Non_Existent_Module " . to_string ( ) ) ;
let rslt = modsmgr . exec_disable ( requestor . clone ( ) ,
None ,
trg_module . clone ( ) ,
trg_level . clone ( ) ,
false ,
Arc ::new ( RwLock ::new ( idmgr ) ) ) . await ;
assert_eq! ( rslt , ChangeResult ::Failed ( " Module doesn't exist " . to_string ( ) ) ) ;
}
2024-03-21 14:01:54 -04:00
}