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 {
statusdb : HashMap < ModType , Vec < ModStatusType > > ,
2024-02-25 10:40:54 -05:00
botactions : HashMap < ModType , Vec < BotAction > > ,
2023-12-22 09:52:01 -05:00
}
- statusdb : HashMap < ModType , Vec < ModStatusType > > - Defines Modules and their ModStatusType ( e . g . , Enabled at an Instance level , Disabled at a Channel Level )
2024-02-25 10:40:54 -05:00
- botactions : HashMap < ModType , 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-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 ;
2024-03-21 00:05:52 -04:00
// use std::error::Error;
2024-03-02 10:24:13 -05:00
use std ::sync ::Arc ;
2023-12-21 00:48:09 -05:00
2024-03-21 09:37:08 -04:00
// use futures::stream::iter;
2023-12-26 20:00:32 -05:00
use twitch_irc ::message ::PrivmsgMessage ;
2023-12-21 00:48:09 -05:00
2024-03-21 14:01:54 -04:00
// use casual_logger::Log;
2024-03-02 10:24:13 -05:00
use tokio ::sync ::RwLock ;
use async_trait ::async_trait ;
2024-03-02 11:41:24 -05:00
use self ::bot_actions ::actions_util ::BotAR ;
2024-03-21 21:20:16 -04:00
use crate ::core ::bot_actions ::actions_util ;
2024-03-21 00:05:52 -04:00
use crate ::core ::botinstance ::{ BotInstance , ChType , ChangeResult } ;
2024-03-02 10:24:13 -05:00
use crate ::core ::botlog ;
2024-03-21 21:20:16 -04:00
use crate ::core ::identity ::{ self , Permissible } ;
2024-02-12 01:25:12 -05:00
2024-03-02 12:21:18 -05:00
use crate ::core ::bot_actions ;
2024-03-02 10:24:13 -05:00
pub use ChType ::Channel ;
pub use ModType ::BotModule ;
2024-03-21 21:20:16 -04:00
use super ::identity ::ChatBadge ;
2024-03-21 00:05:52 -04:00
// use super::identity::ChangeResult;
2024-03-21 21:20:16 -04:00
pub async fn init ( mgr : Arc < ModulesManager > ) {
const OF_CMD_CHANNEL :ChType = Channel ( String ::new ( ) ) ;
// 1. Define the BotAction
let botc1 = BotCommand {
module : BotModule ( String ::from ( " core " ) ) ,
command : String ::from ( " enable " ) , // command call name
alias : vec ! [
String ::from ( " e " ) ,
String ::from ( " en " ) ] , // String of alternative names
exec_body : actions_util ::asyncbox ( cmd_enable ) ,
help : String ::from ( " Test Command tester " ) ,
required_roles : vec ! [
identity ::UserRole ::BotAdmin ,
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ,
} ;
// 2. Add the BotAction to ModulesManager
botc1 . add_core_to_modmgr ( Arc ::clone ( & mgr ) ) . await ;
async fn cmd_enable ( bot : BotAR , msg : PrivmsgMessage ) {
/*
There should be additional validation checks
- BotAdmins can only run instance level ( - i ) enables
- If BotAdmins need to enable / disable at instance level , they must Promote themselves to be a Mod at least
- Other Special Roles ( Mod , SupMod , Broadcaster ) can run without issues to enable the module at Channel Level
* /
/*
enable - i < module > // enables at Instance
enable < module > // enables at Channel
* /
/*
1. Parse out Message Arguments
exec_enable ( )
2. Get Special Roles of CmdSender
3. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
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
* /
/*
exec_enable ( Self , requestor , requestor_badge , trg_module , Channel ) -> ChangeResult
* /
}
// 1. Define the BotAction
let botc1 = BotCommand {
module : BotModule ( String ::from ( " core " ) ) ,
command : String ::from ( " disable " ) , // command call name
alias : vec ! [
String ::from ( " d " ) ] , // String of alternative names
exec_body : actions_util ::asyncbox ( cmd_disable ) ,
help : String ::from ( " Test Command tester " ) ,
required_roles : vec ! [
identity ::UserRole ::BotAdmin ,
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ,
} ;
// 2. Add the BotAction to ModulesManager
botc1 . add_core_to_modmgr ( Arc ::clone ( & mgr ) ) . await ;
async fn cmd_disable ( bot : BotAR , msg : PrivmsgMessage ) {
/*
There should be additional validation checks
- BotAdmins can only run instance level ( - i ) disables
- If BotAdmins need to enable / disable at instance level , they must Promote themselves to be a Mod at least
- Other Special Roles ( Mod , SupMod , Broadcaster ) can run without issues to disable the module at Channel Level
* /
/*
disable - i < module > // disables at Instance
disable < module > // disables at Channel
disable - f < module > // force disables (instance and enabled are removed)
* /
}
}
2024-03-02 10:24:13 -05:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone) ]
pub enum ModType {
BotModule ( String ) ,
}
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-21 02:13:23 -04:00
Ch ( ChType ) ,
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-01 23:36:37 -05:00
pub async fn execute ( & self , m : BotAR , n : PrivmsgMessage ) {
2024-01-29 02:27:11 -05:00
match self {
2024-02-25 10:40:54 -05:00
BotAction ::L ( a ) = > a . execute ( m , n ) . await ,
BotAction ::C ( a ) = > a . execute ( m , n ) . 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-02-25 10:40:54 -05:00
pub module : ModType ,
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-01 23:36:37 -05:00
pub async fn execute ( & self , m : BotAR , n : PrivmsgMessage ) {
( * self . exec_body ) ( m , n ) . 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 {
pub module : ModType ,
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-01 23:36:37 -05:00
pub async fn execute ( & self , m : BotAR , n : PrivmsgMessage ) {
( self . exec_body ) ( m , n ) . 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
}
2023-12-21 00:48:09 -05:00
#[ derive(Debug) ]
2024-03-01 23:36:37 -05:00
pub struct Routine { }
2023-12-21 00:48:09 -05:00
2024-02-25 10:40:54 -05:00
pub struct ModulesManager {
2024-03-20 23:20:46 -04:00
// statusdb: Arc<RwLock<HashMap<ModType, Vec<ModStatusType>>>>,
2024-03-21 00:11:24 -04:00
// statusdb: Arc<RwLock<HashMap<(ModType,ModGroup), Vec<StatusType>>>>,
statusdb : Arc < RwLock < HashMap < ModType , ( ModGroup , Vec < StatusType > ) > > > ,
2024-02-25 10:40:54 -05:00
pub botactions : Arc < RwLock < HashMap < ModType , Vec < BotAction > > > > ,
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
< ModType , < - - 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-02-25 10:40:54 -05:00
ModType , < - - 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 ;
// 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-21 12:21:00 -04:00
pub async fn modstatus ( & self , in_module : ModType , in_chnl : ChType ) -> 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 a = dbt.entry(in_module.clone()).;
let ( mgrp , statusvector ) = dbt . get ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
StatusType ::Enabled ( StatusLvl ::Instance ) // This forces core to be validated as Enabled, even if undesired scenario of missing StatusLvl::Instance or empty vectors
} ,
ModGroup ::Custom = > {
// // remove all instance level pattern for the module
// while let Some(index) = statusvector
// .iter()
// .position(|x| (*x == StatusType::Enabled(StatusLvl::Instance)) || (*x == StatusType::Disabled(StatusLvl::Instance))) {
// statusvector.remove(index);
// }
// statusvector.push(StatusType::Disabled(StatusLvl::Instance));
// (
// StatusType::Disabled(StatusLvl::Instance),
// ChangeResult::Success("Set Disabled at Instance".to_string())
// )
/*
[ x ] 1. If Disabled at Instance Level ,
[ x ] a . And Enabled at a Channel Level > return Enabled ( Channel )
[ x ] b . And Disabled at a Channel Level > return Disabled ( Channel )
[ x ] c . And Not Defined at Channel Level > return Disabled ( Instance )
[ x ] 2. If Enabled at Instance Level ,
[ x ] a . And Enabled at a Channel Level > return Enabled ( Channel )
[ x ] b . And Disabled at a Channel Level > return Disabled ( Channel )
[ x ] c . And Not Defined at Channel Level > return Enabled ( Instance )
* /
if statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Instance ) ) {
// [x] 1. If Disabled at Instance Level ,
if statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] a. And Enabled at a Channel Level > return Enabled(Channel)
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else if statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] b. And Disabled at a Channel Level > return Disabled(Channel)
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else {
// [x] c. And Not Defined at Channel Level > return Disabled(Instance)
StatusType ::Disabled ( StatusLvl ::Instance )
}
} else if statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Instance ) ) {
// [x] 2. If Enabled at Instance Level ,
if statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] a. And Enabled at a Channel Level > return Enabled(Channel)
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else if statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) {
// [x] b. And Disabled at a Channel Level > return Disabled(Channel)
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) )
} else {
// [x] c. And Not Defined at Channel Level > return Enabled(Instance)
StatusType ::Enabled ( StatusLvl ::Instance )
}
} else {
// ? In some unexpected scenario (e.g., not define at instance level), assume Disabled at Instance level and set as this way
self . set_instance_disabled ( in_module ) . await ;
StatusType ::Disabled ( StatusLvl ::Instance )
}
} ,
}
//StatusType::Enabled(StatusLvl::Instance)
2023-12-21 00:48:09 -05:00
}
2024-03-21 00:05:52 -04:00
// pub fn togglestatus(&self, _: ModType, _: ChType) -> StatusType {
// // enables or disables based on current status
// StatusType::Enabled(StatusLvl::Instance)
// }
// pub fn setstatus(&self, _: ModType, _: StatusType) -> Result<&str, Box<dyn Error>> {
// // sets the status based given ModSatusType
// // e.g., b.setstatus(BodModule("GambaCore"), Enabled(Channel("modulatingforce"))).expect("ERROR")
// Ok("")
// }
2024-03-21 21:20:16 -04:00
/*
exec_enable ( self , requestor , requestor_badge , trg_module , Channel ) -> ChangeResult
* /
pub async fn exec_enable (
& self ,
requestor : String ,
requestor_badge : Option < ChatBadge > ,
trg_module : ModType ,
// channel: Option<ChType>,
trg_level : StatusLvl ,
bot : BotAR ,
) -> ChangeResult
{
/*
1. If CmdSender is BotAdmin but not ( Mod , SupMod , Broadcaster )
1. can_user_run for cmdreqRoles including BotAdmin & not can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
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
* /
/*
[ ] 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 - i ( to instance ) , return a Success
1 b . , and is not - i ( to instance ) , return a Failure recommending BotAdmin promote themselves first
* /
let botlock = bot . read ( ) . await ;
let id = botlock . get_identity ( ) ;
let mut idlock = id . write ( ) . await ;
// if trg_level = StatusLvl::Instance , the temp_chnl = the broadcaster's or the chatter's
let arb_chnl = match trg_level . clone ( ) {
StatusLvl ::Instance = > ChType ::Channel ( requestor . to_lowercase ( ) ) ,
StatusLvl ::Ch ( a ) = > a ,
} ;
const OF_CMD_CHANNEL :ChType = Channel ( String ::new ( ) ) ;
let ( admin_level_access , _ ) = idlock . can_user_run ( requestor . clone ( ) , arb_chnl . clone ( ) , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::BotAdmin ,
] ) . await ;
let ( chnl_elevated_access , _ ) = idlock . can_user_run ( requestor , arb_chnl , requestor_badge . clone ( ) ,
vec! [
identity ::UserRole ::Mod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::SupMod ( OF_CMD_CHANNEL ) ,
identity ::UserRole ::Broadcaster ,
] ) . await ;
if let Permissible ::Allow = admin_level_access {
if let Permissible ::Block = chnl_elevated_access {
match trg_level {
StatusLvl ::Instance = > {
self . set_instance_enabled ( trg_module . clone ( ) ) . await ;
ChangeResult ::Success ( " Enabled at Instance Level " . to_string ( ) )
} ,
StatusLvl ::Ch ( _ ) = > {
ChangeResult ::Failed ( " Promote yourself Temporarily First " . to_string ( ) )
} ,
} ;
}
}
/*
[ ] 2. If CmdSender not a BotAdmin but is ( Mod , SupMod , Broadcaster )
2. not can_user_run for cmdreqRoles including BotAdmin & can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster )
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 = > {
ChangeResult ::Failed ( " You're not allowed " . to_string ( ) )
} ,
StatusLvl ::Ch ( in_chnl ) = > {
self . set_ch_enabled ( trg_module . clone ( ) , in_chnl ) . await ;
ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) )
} ,
} ;
}
}
/*
[ ] 3. If CmdSender is ( Mod , SupMod , Broadcaster ) and a BotAdmin
3. can_user_run for cmdreqRoles ( Mod , SupMod , Broadcaster ) & can_user_run for cmdreqRoles including BotAdmin
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 ;
ChangeResult ::Success ( " Enabled at Instance Level " . to_string ( ) )
} ,
StatusLvl ::Ch ( in_chnl ) = > {
self . set_ch_enabled ( trg_module . clone ( ) , in_chnl ) . await ;
ChangeResult ::Success ( " Enabled at Channel Level " . to_string ( ) )
} ,
} ;
}
}
// =======================
// =======================
// =======================
// /*
// 2. Get Special Roles of CmdSender
// 3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
// 3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
// 3b. , and is -i (to instance) , return a Success
// 4. If CmdSender not a BotAdmin but is (Mod,SupMod,Broadcaster)
// 4a. , and is not -i (to instance) , return a Success
// 4b. , and is -i (to instance) , return a Failure they are not allowed
// 5. If CmdSender is (Mod,SupMod,Broadcaster) and a BotAdmin
// 5a. , and is not -i (to instance) , return a Success
// 5b. , and is -i (to instance) , return a Success
// */
// // [ ] 2. Get Special Roles of CmdSender
// let botlock = bot.read().await;
// let id = botlock.get_identity();
// let idlock = id.read().await;
// let trgchnl = {
// match trg_level {
// StatusLvl::Instance => None,
// StatusLvl::Ch(a) => Some(a),
// }
// };
// let requestor_roles = idlock
// .getspecialuserroles(
// requestor.to_lowercase(),
// trgchnl,
// )
// .await;
// /*
// [ ] 3. If CmdSender is BotAdmin but not (Mod,SupMod,Broadcaster)
// 3a. , and is not -i (to instance) , return a Failure recommending BotAdmin promote themselves first
// 3b. , and is -i (to instance) , return a Success
// */
// if requestor_roles.contains(&identity::UserRole::BotAdmin)
// && !requestor_roles.contains(&identity::UserRole::Broadcaster)
// && !requestor_roles.contains(&identity::UserRole::Mod(trgchnl))
// {
// }
ChangeResult ::NoChange ( " ERROR : Not implemented yet " . to_string ( ) )
}
2024-03-21 02:13:23 -04:00
pub async fn set_instance_disabled ( & self , in_module : ModType ) -> ( 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
// self.satusdb.
let mut dbt = self . statusdb . write ( ) . await ;
// let a = dbt.entry(in_module.clone()).;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Failed ( " Core Modules cannot be disabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all instance level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x | ( * x = = StatusType ::Enabled ( StatusLvl ::Instance ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Instance ) ) ) {
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
(
StatusType ::Disabled ( StatusLvl ::Instance ) ,
2024-03-21 12:21:00 -04:00
ChangeResult ::Success ( " Set Disabled at Instance " . to_string ( ) )
2024-03-21 02:13:23 -04:00
)
} ,
}
// (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
2023-12-21 00:48:09 -05:00
}
2024-03-21 02:13:23 -04:00
pub async fn force_disable ( & self , in_module : ModType ) -> ( StatusType , ChangeResult ) {
// 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 a = dbt.entry(in_module.clone()).;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Failed ( " Core Modules cannot be disabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all instance level pattern & Enabled Channel patterns for the module
// Disabled at Channel level might be fine? That way if it gets Enabled at instance level, channel level disables are uninterrupted
while let Some ( index ) = statusvector
. iter ( )
. position ( | x |
if ( * x = = StatusType ::Enabled ( StatusLvl ::Instance ) )
| | ( * x = = StatusType ::Disabled ( StatusLvl ::Instance ) ) {
true
} else if let StatusType ::Enabled ( StatusLvl ::Ch ( _ ) ) = ( * x ) . clone ( ) {
true
} else { false }
)
{
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
(
StatusType ::Disabled ( StatusLvl ::Instance ) ,
2024-03-21 09:37:08 -04:00
ChangeResult ::Success ( " Forced Disabled " . to_string ( ) )
2024-03-21 02:13:23 -04:00
)
} ,
}
// (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
2023-12-21 00:48:09 -05:00
}
2024-03-21 12:21:00 -04:00
pub async fn set_instance_enabled ( & self , in_module : ModType ) -> ( 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 a = dbt.entry(in_module.clone()).;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::NoChange ( " Core Modules are always Enabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all instance level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x | ( * x = = StatusType ::Enabled ( StatusLvl ::Instance ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Instance ) ) ) {
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Success ( " Set Enabled at Instance " . to_string ( ) )
)
} ,
}
// (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
2024-03-21 00:05:52 -04:00
}
2024-03-21 12:21:00 -04:00
pub async fn set_ch_disabled ( & self , in_module : ModType , in_chnl : ChType ) -> ( 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 a = dbt.entry(in_module.clone()).;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::Failed ( " Core Modules cannot be disabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all channel level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x |
( * x = = StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) )
{
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) ;
(
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ,
ChangeResult ::Success ( " Set Disabled at Channel Level " . to_string ( ) )
)
} ,
}
// (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
2024-03-21 00:05:52 -04:00
}
2024-03-21 12:21:00 -04:00
pub async fn set_ch_enabled ( & self , in_module : ModType , in_chnl : ChType ) -> ( 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 a = dbt.entry(in_module.clone()).;
let ( mgrp , statusvector ) = dbt . get_mut ( & in_module ) . unwrap ( ) ;
match mgrp {
ModGroup ::Core = > {
(
StatusType ::Enabled ( StatusLvl ::Instance ) ,
ChangeResult ::NoChange ( " Core Modules are always Enabled " . to_string ( ) )
)
} ,
ModGroup ::Custom = > {
// remove all channel level pattern for the module
while let Some ( index ) = statusvector
. iter ( )
. position ( | x |
( * x = = StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) | | ( * x = = StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) )
{
statusvector . remove ( index ) ;
}
statusvector . push ( StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ) ;
(
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl . clone ( ) ) ) ,
ChangeResult ::Success ( " Set Enabled at Channel Level " . to_string ( ) )
)
} ,
}
// (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string()))
2024-03-21 00:05:52 -04:00
}
2024-02-25 10:40:54 -05:00
pub async fn add_botaction ( & self , in_module : ModType , in_action : BotAction ) {
2024-03-20 23:20:46 -04:00
self . int_add_botaction ( in_module , ModGroup ::Custom , in_action ) . await ;
}
pub async fn add_core_act ( & self , in_module : ModType , in_action : BotAction ) {
self . int_add_botaction ( in_module , ModGroup ::Core , in_action ) . await ;
}
2024-03-21 02:13:23 -04:00
pub async fn affirm_in_statusdb ( & self , in_module :ModType , in_modgroup : ModGroup ) {
let mut dbt = self . statusdb . write ( ) . await ;
let ( _ , statusvector ) = dbt . entry ( in_module . clone ( ) ) . or_insert ( ( in_modgroup . clone ( ) , Vec ::new ( ) ) ) ;
if ! statusvector . contains ( & StatusType ::Enabled ( StatusLvl ::Instance ) ) & & ! statusvector . contains ( & StatusType ::Disabled ( StatusLvl ::Instance ) )
{
match in_modgroup {
ModGroup ::Core = > statusvector . push ( StatusType ::Enabled ( StatusLvl ::Instance ) ) , // Pushes the Module as Enabled at Instance Level
ModGroup ::Custom = > statusvector . push ( StatusType ::Disabled ( StatusLvl ::Instance ) ) ,
}
}
}
2024-03-20 23:20:46 -04:00
async fn int_add_botaction ( & self , in_module : ModType , 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-02-25 10:40:54 -05:00
async fn find_conflict_module ( mgr : & ModulesManager , act : & BotAction ) -> Option < ModType > {
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-01-29 04:28:58 -05:00
for modact in moduleactions . iter ( ) {
if let BotAction ::C ( dbcmd ) = & modact {
// 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
// let mut dbt = self.statusdb.write().await;
// //
// let statusvector = dbt.entry(in_module.clone()).or_insert((in_modgroup.clone(),Vec::new()));
2023-12-21 17:22:40 -05:00
2024-03-21 02:13:23 -04:00
// match in_modgroup {
// ModGroup::Core => statusvector.1.push(StatusType::Enabled(StatusLvl::Instance)) , // Pushes the Module as Enabled at Instance Level
// ModGroup::Custom => statusvector.1.push(StatusType::Disabled(StatusLvl::Instance)),
// }
2024-03-20 23:32:05 -04:00
// statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level
2023-12-21 17:22:40 -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
2023-12-21 20:11:32 -05:00
modactions . push ( 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-01 23:36:37 -05:00
fn _statuscleanup ( & self , _ : Option < ChType > ) {
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
// Option<ChType> can pass Some(Channel("m")) (as an example) so statuscleanup only works on the given channel
// Passing None to chnl may be a heavy operation, as this will review and look at the whole table
}
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 ::* ;
/*
Possible Tests
[ x ] Test 1 - Custom ModGroup Workflow
1. affirm_in_statusdb ( Experiments01 , Custom )
2. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
3. set_instance_enabled ( Experiments01 )
4. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
5. set_ch_disabled ( Experiments01 , TestChannel01 )
6. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
7. set_ch_enabled ( Experiments01 , TestChannel01 ) & set_ch_disabled ( Experiments01 , TestChannel02 )
8. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
9. set_instance_disabled ( Experiments01 )
10. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
11. force_disable ( Experiments01 )
12. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
[ x ] Test 2 - Core ModGroup Workflow
1. affirm_in_statusdb ( CoreModule01 , Core )
2. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
3. set_instance_enabled ( CoreModule01 )
4. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
5. set_ch_disabled ( CoreModule01 , TestChannel01 )
6. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
7. set_ch_enabled ( CoreModule01 , TestChannel01 ) & set_ch_disabled ( CoreModule01 , TestChannel02 )
8. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
9. set_instance_disabled ( CoreModule01 )
10. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
11. force_disable ( CoreModule01 )
12. modstatus ( CoreModule01 , TestChannel01 ) & modstatus ( CoreModule01 , TestChannel02 )
* /
async fn complex_workflow (
in_module : ModType ,
in_modgroup : ModGroup ,
in_chnl1 : ChType ,
in_chnl2 : ChType )
{
let mgr = ModulesManager ::init ( ) . await ;
/*
1. affirm_in_statusdb ( Experiments01 , Custom )
2. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . affirm_in_statusdb ( in_module . clone ( ) , in_modgroup . clone ( ) ) . await ;
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
3. set_instance_enabled ( Experiments01 )
4. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_instance_enabled ( in_module . clone ( ) ) . await ;
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
5. set_ch_disabled ( Experiments01 , TestChannel01 )
6. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_ch_disabled ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ;
//StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Ch ( in_chnl1 . clone ( ) ) ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
7. set_ch_enabled ( Experiments01 , TestChannel01 ) & set_ch_disabled ( Experiments01 , TestChannel02 )
8. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_ch_enabled ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ;
//StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl1 . clone ( ) ) ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
9. set_instance_disabled ( Experiments01 )
10. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . set_instance_disabled ( in_module . clone ( ) ) . await ;
// StatusType::Disabled(StatusLvl::Ch(in_chnl1.clone()))
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Ch ( in_chnl1 . clone ( ) ) ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
/*
11. force_disable ( Experiments01 )
12. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
mgr . force_disable ( in_module . clone ( ) ) . await ;
match in_modgroup {
ModGroup ::Custom = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Disabled ( StatusLvl ::Instance ) ) ;
} ,
ModGroup ::Core = > {
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl1 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
assert_eq! ( mgr . modstatus ( in_module . clone ( ) , in_chnl2 . clone ( ) ) . await ,
StatusType ::Enabled ( StatusLvl ::Instance ) ) ;
} ,
}
}
#[ tokio::test ]
async fn custom_modgroup_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
/*
[ x ] Test 1 - Custom ModGroup Workflow
1. affirm_in_statusdb ( Experiments01 , Custom )
2. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
3. set_instance_enabled ( Experiments01 )
4. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
5. set_ch_disabled ( Experiments01 , TestChannel01 )
6. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
7. set_ch_enabled ( Experiments01 , TestChannel01 ) & set_ch_disabled ( Experiments01 , TestChannel02 )
8. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
9. set_instance_disabled ( Experiments01 )
10. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
11. force_disable ( Experiments01 )
12. modstatus ( Experiments01 , TestChannel01 ) & modstatus ( Experiments01 , TestChannel02 )
* /
let in_module = BotModule ( " Experiments01 " . to_string ( ) ) ;
let in_modgroup = ModGroup ::Custom ;
let ( in_chnl1 , in_chnl2 ) =
( ChType ::Channel ( " TestChannel01 " . to_string ( ) ) , ChType ::Channel ( " TestChannel02 " . to_string ( ) ) ) ;
complex_workflow ( in_module , in_modgroup , in_chnl1 , in_chnl2 ) . await ;
}
#[ tokio::test ]
async fn core_modgroup_workflow ( ) {
Log ::set_file_ext ( Extension ::Log ) ;
let in_module = BotModule ( " CoreModule01 " . to_string ( ) ) ;
let in_modgroup = ModGroup ::Core ;
let ( in_chnl1 , in_chnl2 ) =
( ChType ::Channel ( " TestChannel01 " . to_string ( ) ) , ChType ::Channel ( " TestChannel02 " . to_string ( ) ) ) ;
complex_workflow ( in_module , in_modgroup , in_chnl1 , in_chnl2 ) . await ;
}
}