update module management

This commit is contained in:
adator
2025-11-01 17:39:16 +01:00
parent 8abae5df3e
commit 2fbe75b83e
4 changed files with 93 additions and 155 deletions

View File

@@ -1,7 +1,6 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from dataclasses import dataclass from dataclasses import dataclass
from mods.clone.schemas import ModConfModel from mods.clone.schemas import ModConfModel
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -23,6 +22,9 @@ class IModule(ABC):
# Add Irc Object to the module (Mandatory) # Add Irc Object to the module (Mandatory)
self.Irc = uplink self.Irc = uplink
# Add Loader object to the module (Mandatory)
self.Loader = uplink.Loader
# Add Protocol to the module (Mandatory) # Add Protocol to the module (Mandatory)
self.Protocol = uplink.Protocol self.Protocol = uplink.Protocol
@@ -41,19 +43,25 @@ class IModule(ABC):
# Add User object to the module (Mandatory) # Add User object to the module (Mandatory)
self.User = uplink.User self.User = uplink.User
# Add Client object to the module (Mandatory)
self.Client = uplink.Client
# Add Channel object to the module (Mandatory) # Add Channel object to the module (Mandatory)
self.Channel = uplink.Channel self.Channel = uplink.Channel
# Add Reputation object to the module (Optional) # Add Reputation object to the module (Optional)
self.Reputation = uplink.Reputation self.Reputation = uplink.Reputation
self.ModConfig = ModConfModel() # Load the child classes
self.load()
self.load_module_configuration() # Inspect child classes
"""Load module configuration""" self.inspect_class()
# Init the ModConfig model object.
self.ModConfig:ModConfModel = ModConfModel()
self.create_tables() self.create_tables()
"""Create custom module tables"""
# Sync the configuration with core configuration (Mandatory) # Sync the configuration with core configuration (Mandatory)
uplink.Base.db_sync_core_config(self.module_name, self.ModConfig) uplink.Base.db_sync_core_config(self.module_name, self.ModConfig)
@@ -70,32 +78,27 @@ class IModule(ABC):
""" """
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value)
def inspect_class(self):
if not hasattr(self, 'ModConfig'):
raise AttributeError("The Module must init ModConfig attribute in the load method!")
@abstractmethod @abstractmethod
def create_tables(self) -> None: def create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas. """
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module Method that will create the database if it does not exist.
A single Session for this class will be created, which will be used within this class/module.
Args: Args:
database_name (str): Nom de la base de données ( pas d'espace dans le nom ) database_name (str): Name of the database (no spaces allowed in the name)
Returns: Returns:
None: Aucun retour n'es attendu None: No return is expected
""" """
@abstractmethod @abstractmethod
def load_module_configuration(self) -> None: def load(self) -> None:
"""### Load Module Configuration """This method is executed when the module is loaded or reloaded.
""" """
try:
# Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel(jsonrpc=0)
# Sync the configuration with core configuration (Mandatory)
self.Base.db_sync_core_config(self.module_name, self.ModConfig)
return None
except TypeError as te:
self.Logs.critical(te)
@abstractmethod @abstractmethod
def unload(self) -> None: def unload(self) -> None:

View File

@@ -66,9 +66,19 @@ class Module:
return self.reload_one_module(uplink, module_name, nickname) return self.reload_one_module(uplink, module_name, nickname)
# Charger le module # Charger le module
loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') try:
my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}')
create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe
create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe
except AttributeError as attr:
red = uplink.Config.COLORS.red
nogc = uplink.Config.COLORS.nogc
uplink.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME,
msg=f"[{red}MODULE ERROR{nogc}] Module {module_name} is facing issues ! {attr}",
channel=self.__Config.SERVICE_CHANLOG
)
return False
if not hasattr(create_instance_of_the_class, 'cmd'): if not hasattr(create_instance_of_the_class, 'cmd'):
uplink.Protocol.send_priv_msg( uplink.Protocol.send_priv_msg(

View File

@@ -1,13 +1,12 @@
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from dataclasses import dataclass from dataclasses import dataclass
from core.classes.interfaces.imodule import IModule
import mods.command.utils as utils import mods.command.utils as utils
if TYPE_CHECKING: if TYPE_CHECKING:
from core.irc import Irc
from core.definition import MUser from core.definition import MUser
from sqlalchemy import CursorResult, Row, Sequence
class Command: class Command(IModule):
@dataclass @dataclass
class ModConfModel: class ModConfModel:
@@ -15,44 +14,44 @@ class Command:
""" """
pass pass
def __init__(self, ircInstance: 'Irc') -> None: def create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas.
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
Args:
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
# Module name (Mandatory) Returns:
self.module_name = 'mod_' + str(self.__class__.__name__).lower() None: Aucun retour n'es attendu
"""
# Add Irc Object to the module (Mandatory) table_automode = '''CREATE TABLE IF NOT EXISTS command_automode (
self.Irc = ircInstance id INTEGER PRIMARY KEY AUTOINCREMENT,
created_on TEXT,
updated_on TEXT,
nickname TEXT,
channel TEXT,
mode TEXT
)
'''
# Add Loader Object to the module (Mandatory) self.Base.db_execute_query(table_automode)
self.Loader = ircInstance.Loader return None
# Add Protocol object to the module (Mandatory)
self.Protocol = ircInstance.Protocol
# Add Global Configuration to the module (Mandatory)
self.Config = ircInstance.Config
# Add Base object to the module (Mandatory)
self.Base = ircInstance.Base
# Add main Utils to the module
self.MainUtils = ircInstance.Utils
# Add logs object to the module (Mandatory)
self.Logs = ircInstance.Loader.Logs
# Add User object to the module (Mandatory)
self.User = ircInstance.User
# Add Client object to the module (Mandatory)
self.Client = ircInstance.Client
# Add Channel object to the module (Mandatory)
self.Channel = ircInstance.Channel
def load(self) -> None:
# Module Utils # Module Utils
self.mod_utils = utils self.mod_utils = utils
# Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel()
self.user_to_notice: str = ''
self.show_219: bool = True
# Register new commands into the protocol
new_cmds = {'403', '401', '006', '018', '219', '223'}
for c in new_cmds:
self.Irc.Protocol.known_protocol.add(c)
self.Irc.build_command(2, self.module_name, 'join', 'Join a channel') self.Irc.build_command(2, self.module_name, 'join', 'Join a channel')
self.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task') self.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task')
self.Irc.build_command(2, self.module_name, 'part', 'Leave a channel') self.Irc.build_command(2, self.module_name, 'part', 'Leave a channel')
@@ -104,73 +103,6 @@ class Command:
self.Irc.build_command(2, self.module_name, 'klinelist', 'List all K-line bans') self.Irc.build_command(2, self.module_name, 'klinelist', 'List all K-line bans')
self.Irc.build_command(3, self.module_name, 'map', 'Show the server network map') self.Irc.build_command(3, self.module_name, 'map', 'Show the server network map')
# Init the module
self.__init_module()
# Log the module
self.Logs.debug(f'-- Module {self.module_name} loaded ...')
def __init_module(self) -> None:
# Create you own tables (Mandatory)
self.__create_tables()
# Load module configuration and sync with core one (Mandatory)
self.__load_module_configuration()
# End of mandatory methods you can start your customization #
self.user_to_notice: str = ''
self.show_219: bool = True
return None
def __create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas.
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
Args:
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
Returns:
None: Aucun retour n'es attendu
"""
table_automode = '''CREATE TABLE IF NOT EXISTS command_automode (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_on TEXT,
updated_on TEXT,
nickname TEXT,
channel TEXT,
mode TEXT
)
'''
self.Base.db_execute_query(table_automode)
return None
def __load_module_configuration(self) -> None:
"""### Load Module Configuration
"""
try:
# Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel()
# Sync the configuration with core configuration (Mandatory)
self.Base.db_sync_core_config(self.module_name, self.ModConfig)
return None
except TypeError as te:
self.Logs.critical(te)
def __update_configuration(self, param_key: str, param_value: str):
"""Update the local and core configuration
Args:
param_key (str): The parameter key
param_value (str): The parameter value
"""
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value)
def unload(self) -> None: def unload(self) -> None:
self.Irc.Commands.drop_command_by_module(self.module_name) self.Irc.Commands.drop_command_by_module(self.module_name)
return None return None
@@ -186,10 +118,12 @@ class Command:
nogc = self.Config.COLORS.nogc nogc = self.Config.COLORS.nogc
cmd = list(data).copy() cmd = list(data).copy()
if len(cmd) < 2: pos, parsed_cmd = self.Irc.Protocol.get_ircd_protocol_poisition(cmd=cmd, log=True)
if pos == -1:
return None return None
match cmd[1]: match parsed_cmd:
# [':irc.deb.biz.st', '403', 'Dev-PyDefender', '#Z', ':No', 'such', 'channel'] # [':irc.deb.biz.st', '403', 'Dev-PyDefender', '#Z', ':No', 'such', 'channel']
case '403' | '401': case '403' | '401':
try: try:
@@ -260,22 +194,10 @@ class Command:
except Exception as err: except Exception as err:
self.Logs.warning(f'Unknown Error: {str(err)}') self.Logs.warning(f'Unknown Error: {str(err)}')
case _:
pass
if len(cmd) < 3:
return None
match cmd[2]:
case 'SJOIN': case 'SJOIN':
# ['@msgid=yldTlbwAGbzCGUcCIHi3ku;time=2024-11-11T17:56:24.297Z', ':001', 'SJOIN', '1728815963', '#znc', ':001LQ0L0C'] # ['@msgid=yldTlbwAGbzCGUcCIHi3ku;time=2024-11-11T17:56:24.297Z', ':001', 'SJOIN', '1728815963', '#znc', ':001LQ0L0C']
# Check if the user has an automode # Check if the user has an automode
try: try:
if len(cmd) < 6:
return None
user_uid = self.User.clean_uid(cmd[5]) user_uid = self.User.clean_uid(cmd[5])
userObj: MUser = self.User.get_user(user_uid) userObj: MUser = self.User.get_user(user_uid)
channel_name = cmd[4] if self.Channel.is_valid_channel(cmd[4]) else None channel_name = cmd[4] if self.Channel.is_valid_channel(cmd[4]) else None
@@ -301,6 +223,9 @@ class Command:
except KeyError as ke: except KeyError as ke:
self.Logs.error(f"Key Error: {err}") self.Logs.error(f"Key Error: {err}")
case _:
pass
except Exception as err: except Exception as err:
self.Logs.error(f"General Error: {err}") self.Logs.error(f"General Error: {err}")

View File

@@ -6,25 +6,12 @@ class Test(IModule):
@dataclass @dataclass
class ModConfModel: class ModConfModel:
"""The Model containing the module parameters """The Model containing the module parameters
you can leave it without params.
just use pass | if you leave it empty, in the load() method just init empty object ==> self.ModConfig = ModConfModel()
""" """
param_exemple1: str param_exemple1: str
param_exemple2: int param_exemple2: int
def load_module_configuration(self) -> None:
"""### Load Module Configuration
"""
# Create module commands (Mandatory)
self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command')
self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command')
self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command')
self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command')
# Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1)
return None
def create_tables(self) -> None: def create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas. """Methode qui va créer la base de donnée si elle n'existe pas.
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
@@ -45,6 +32,19 @@ class Test(IModule):
# self.Base.db_execute_query(table_logs) # self.Base.db_execute_query(table_logs)
return None return None
def load(self) -> None:
"""### Load Module Configuration
"""
# Create module commands (Mandatory)
self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command')
self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command')
self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command')
self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command')
# Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1)
def unload(self) -> None: def unload(self) -> None:
self.Irc.Commands.drop_command_by_module(self.module_name) self.Irc.Commands.drop_command_by_module(self.module_name)
return None return None