# coding=utf-8
# Help Module for drastikbot modules.
#
# This module provides help messages for the loaded drastikbot modules.
#
# Usage
# -----
# Calling the command without arguments returns a list of all the
# loaded modules with help information. Example: .help
#
# Giving the name of a module as an argument returns the available
# bot_commands of that module. Example: .help text
#
# Giving the name of a module followed by one of its bot_commands
# returns a help message of that command: Example: .help text ae
#
# API
# ---
# To provide help messages through this module other modules must
# include the manual variable in their Module class. If no such
# variable is provided the module will be unlisted.
# Copyright (C) 2021 drastik.org
#
# This file is part of drastikbot.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, version 3 only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
import itertools
class Module:
def __init__(self):
self.commands = ["help"]
def get_module_object(i, module_name):
# drastikbot v2.2
if hasattr(i, "mod"):
for mod_object, mod_path in i.mod["modules_d"].values():
if mod_path.stem == module_name:
return mod_object
# drastikbot v2.1
if hasattr(i, "modules") and module_name in i.modules:
return i.modules[module_name]
return None
def hidden_status(i, module_name: str) -> bool:
"""Is ``module'' a hidden module?"""
module_object = get_module_object(i, module_name)
if module_object is None:
return True # Module not found
if not hasattr(module_object, "Module"):
return True # No Module class, it's hidden
if hasattr(module_object.Module(), "manual"):
return module_object.Module().manual
elif hasattr(module_object.Module(), "helpmsg"): # Old method
if "__hidden__" in module_object.Module().helpmsg:
return "hidden"
def is_hidden(i, module_name):
return hidden_status(i, module_name) == "hidden"
def module_checks(i, irc, module):
if module not in i.modules.keys():
irc.notice(i.channel, f"Help: `{module}' is not an imported module.")
return False
try:
module_bl = irc.var.modules_obj["blacklist"][module]
if module_bl and i.channel in module_bl:
irc.notice(i.channel, f"Help: This module has been disabled.")
return False
except KeyError:
pass # No blacklist, move on
try:
module_wl = irc.var.modules_obj["whitelist"][module]
if module_wl and i.channel not in module_wl:
irc.notice(i.channel, f"Help: This module has been disabled.")
return False
except KeyError:
pass # No whitelist, move on
module_c = i.modules[module].Module()
if not hasattr(module_c, "manual"):
irc.notice(i.channel, "Help: This module does not have a manual.")
return False
return True
def module_help(i, irc, module):
if not module_checks(i, irc, module):
return
module_c = i.modules[module].Module()
commands = ""
if hasattr(module_c, "commands"):
commands = ", ".join(module_c.commands)
commands = f"Commands: {commands} | "
info = ""
if "desc" in module_c.manual:
info = module_c.manual["desc"]
info = f"Info: {info}"
t = f"\x0311{module}\x0F: {commands}{info}"
t += f" | Use: {i.cmd_prefix}help for command info."
irc.notice(i.channel, t)
def command_help(i, irc, module, command):
if not module_checks(i, irc, module):
return
module_c = i.modules[module].Module()
if not hasattr(module_c, "commands"):
irc.notice(i.channel, "Help: This module does not provide commands.")
return
if "bot_commands" not in module_c.manual:
irc.notice(i.channel, "Help: No manual entry for this command ")
return
command_manual = module_c.manual["bot_commands"]
if command not in command_manual:
irc.notice(i.channel, "Help: No manual entry for this command.")
return
command_entry = command_manual[command]
t = []
if "usage" in command_entry:
usage = command_entry["usage"](i.cmd_prefix)
usage = f"Usage: {usage}"
t.append(usage)
if "info" in command_entry:
info = command_entry["info"]
info = f"Info: {info}"
t.append(info)
if "alias" in command_entry:
alias = ", ".join(command_entry["alias"])
alias = f"Aliases: {alias}"
t.append(alias)
t = " | ".join(t)
t = f"{command}: {t}"
irc.notice(i.channel, t)
def module_list(i, irc):
m1 = filter(lambda x: not is_hidden(i, x) and i.whitelist(x, i.channel) \
and not i.blacklist(x, i.channel),
set(i.command_dict.values()))
m2 = filter(lambda x: not is_hidden(i, x) and i.whitelist(x, i.channel) \
and not i.blacklist(x, i.channel) and not x in m1,
i.auto_list)
m = itertools.chain(m1, m2)
t = "Help: " + ", ".join(sorted(m))
t += f" | Use: {i.cmd_prefix}help for module info."
irc.notice(i.channel, t)
def main(i, irc):
if i.msg_nocmd:
argv = i.msg_nocmd.split()
argc = len(argv)
if argc == 1:
module_help(i, irc, argv[0])
elif argc == 2:
command_help(i, irc, argv[0], argv[1])
else:
m = f"Usage: {i.cmd_prefix}help [module] [command]"
irc.notice(i.channel, m)
else:
module_list(i, irc)