Compare commits
4 Commits
af08fe0f16
...
d06b8f2fdc
Author | SHA1 | Date | |
---|---|---|---|
d06b8f2fdc | |||
c09b4c04d3 | |||
bf6e5784f2 | |||
6a067166fe |
151
bot.py
151
bot.py
|
@ -62,9 +62,6 @@ class Fulvia(irc.IRCClient):
|
||||||
in them.
|
in them.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.users = tools.FulviaMemory()
|
|
||||||
"""A dictionary of all users the bot is aware of."""
|
|
||||||
|
|
||||||
self.memory = tools.FulviaMemory()
|
self.memory = tools.FulviaMemory()
|
||||||
"""
|
"""
|
||||||
A thread-safe general purpose dictionary to be used by whatever
|
A thread-safe general purpose dictionary to be used by whatever
|
||||||
|
@ -76,12 +73,6 @@ class Fulvia(irc.IRCClient):
|
||||||
A class with some basic interactions for the bot's sqlite3 databse.
|
A class with some basic interactions for the bot's sqlite3 databse.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._callables = {}
|
|
||||||
"""
|
|
||||||
A dictionary containing all callable functions loaded from
|
|
||||||
modules. Keys are the functions name.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self._hooks = []
|
self._hooks = []
|
||||||
"""
|
"""
|
||||||
A list containing all function names to be hooked with every message
|
A list containing all function names to be hooked with every message
|
||||||
|
@ -120,7 +111,6 @@ class Fulvia(irc.IRCClient):
|
||||||
Find and load all of our modules.
|
Find and load all of our modules.
|
||||||
"""
|
"""
|
||||||
print(f"Loading modules...")
|
print(f"Loading modules...")
|
||||||
self._callables = {}
|
|
||||||
self._hooks = []
|
self._hooks = []
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
self._times = {}
|
self._times = {}
|
||||||
|
@ -152,20 +142,11 @@ class Fulvia(irc.IRCClient):
|
||||||
convenient table.
|
convenient table.
|
||||||
"""
|
"""
|
||||||
if hasattr(func, 'commands'):
|
if hasattr(func, 'commands'):
|
||||||
self._callables[func.__name__] = func
|
|
||||||
for cmd in func.commands:
|
for cmd in func.commands:
|
||||||
self.commands[cmd] = tools.Command(cmd)
|
self.commands[cmd] = func
|
||||||
self.commands[cmd]._func_name = func.__name__
|
|
||||||
self.commands[cmd].priv = func.priv
|
|
||||||
self.commands[cmd].doc = func._docs
|
|
||||||
if cmd in func.aliases:
|
|
||||||
self.commands[cmd].canonical = False
|
|
||||||
aliases = [a for a in func.commands if a != cmd]
|
|
||||||
self.commands[cmd].aliases = aliases
|
|
||||||
|
|
||||||
if func.hook:
|
if func.hook:
|
||||||
self._callables[func.__name__] = func
|
self._hooks.append(func)
|
||||||
self._hooks.append(func.__name__)
|
|
||||||
|
|
||||||
if func.rate or func.channel_rate or func.global_rate:
|
if func.rate or func.channel_rate or func.global_rate:
|
||||||
self._times[func.__name__] = {}
|
self._times[func.__name__] = {}
|
||||||
|
@ -187,12 +168,10 @@ class Fulvia(irc.IRCClient):
|
||||||
return
|
return
|
||||||
|
|
||||||
if hasattr(func, 'commands'):
|
if hasattr(func, 'commands'):
|
||||||
self._callables.pop(func.__name__)
|
|
||||||
for command in func.commands:
|
for command in func.commands:
|
||||||
self.commands.pop(command)
|
self.commands.pop(command)
|
||||||
|
|
||||||
if func.hook:
|
if func.hook:
|
||||||
self._callables.pop(func.__name__)
|
|
||||||
self._hooks.remove(func.__name__)
|
self._hooks.remove(func.__name__)
|
||||||
|
|
||||||
if func.rate or func.channel_rate or func.global_rate:
|
if func.rate or func.channel_rate or func.global_rate:
|
||||||
|
@ -261,26 +240,25 @@ class Fulvia(irc.IRCClient):
|
||||||
"""
|
"""
|
||||||
nick = user.partition("!")[0].partition("@")[0]
|
nick = user.partition("!")[0].partition("@")[0]
|
||||||
if channel.startswith("#"):
|
if channel.startswith("#"):
|
||||||
opSym = tools.getOpSym(self.channels[channel].privileges[nick])
|
opSym = self.channels[channel].users[nick].op_level
|
||||||
else:
|
else:
|
||||||
opSym = ""
|
opSym = ''
|
||||||
channel = nick
|
channel = nick
|
||||||
line = "<" + opSym + nick + ">" + " " + message
|
line = f"<{opSym}{nick}> {message}"
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
func_names = []
|
funcs = []
|
||||||
if message.startswith(self.prefix) and message != self.prefix:
|
if message.startswith(self.prefix) and message != self.prefix:
|
||||||
command, _, _ = message.partition(" ")
|
command = message.partition(" ")[0]
|
||||||
command = command.replace(self.prefix, "", 1)
|
command = command.replace(self.prefix, "", 1)
|
||||||
cmd = self.commands.get(command)
|
cmd = self.commands.get(command)
|
||||||
if not cmd:
|
if not cmd:
|
||||||
return
|
return
|
||||||
func_names.append(cmd._func_name)
|
funcs.append(cmd)
|
||||||
|
|
||||||
func_names += self._hooks
|
funcs += self._hooks
|
||||||
|
|
||||||
for func_name in func_names:
|
for func in funcs:
|
||||||
func = self._callables[func_name]
|
|
||||||
trigger = Trigger(user, channel, message, "PRIVMSG", self.config)
|
trigger = Trigger(user, channel, message, "PRIVMSG", self.config)
|
||||||
bot = FulviaWrapper(self, trigger)
|
bot = FulviaWrapper(self, trigger)
|
||||||
|
|
||||||
|
@ -311,19 +289,20 @@ class Fulvia(irc.IRCClient):
|
||||||
|
|
||||||
def joined(self, channel):
|
def joined(self, channel):
|
||||||
"""Called when the bot joins a new channel."""
|
"""Called when the bot joins a new channel."""
|
||||||
line = "-!- " + self.nickname + " " + "[" + self.username + "@"
|
line = f"-!- {self.nickname} [{self.username}@{self.host}] "
|
||||||
line += self.host + "] has joined " + channel
|
line += f"has joined {channel}"
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
print(f"Joined {channel}")
|
print(f"Joined {channel}")
|
||||||
if channel not in self.channels:
|
self.channels[channel] = tools.Channel(channel)
|
||||||
self.channels[channel] = tools.Channel(channel)
|
user = tools.User(self.nickname)
|
||||||
|
self.channels[channel].users[self.nickname] = user
|
||||||
|
|
||||||
|
|
||||||
def left(self, channel, reason=""):
|
def left(self, channel, reason=""):
|
||||||
"""Called when the bot leaves a channel."""
|
"""Called when the bot leaves a channel."""
|
||||||
line = "-!- " + self.nickname + " " + "[" + self.username + "@"
|
line = f"-!- {self.nickname} [{self.username}@{self.host}] "
|
||||||
line += self.host + "] has left " + channel + " [" + reason + "]"
|
line += f"has left {channel} [{reason}]"
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
print(f"Parted {channel}")
|
print(f"Parted {channel}")
|
||||||
|
@ -338,7 +317,7 @@ class Fulvia(irc.IRCClient):
|
||||||
|
|
||||||
def modeChanged(self, user, channel, add_mode, modes, args):
|
def modeChanged(self, user, channel, add_mode, modes, args):
|
||||||
"""Called when users or channel's modes are changed."""
|
"""Called when users or channel's modes are changed."""
|
||||||
line = "-!- mode/" + channel + " ["
|
line = f"-!- mode/{channel} ["
|
||||||
if add_mode:
|
if add_mode:
|
||||||
line += "+"
|
line += "+"
|
||||||
else:
|
else:
|
||||||
|
@ -361,11 +340,11 @@ class Fulvia(irc.IRCClient):
|
||||||
|
|
||||||
elif mode in tools.op_level.keys(): # user mode, op_level mode
|
elif mode in tools.op_level.keys(): # user mode, op_level mode
|
||||||
nick = args[n]
|
nick = args[n]
|
||||||
op_level = tools.op_level[mode]
|
user = self.channels[channel].users[nick]
|
||||||
if add_mode:
|
if add_mode:
|
||||||
self.channels[channel].privileges[nick] += op_level
|
user.op_level += mode
|
||||||
else:
|
else:
|
||||||
self.channels[channel].privileges[nick] -= op_level
|
user.op_level.replace(mode, '', 1)
|
||||||
|
|
||||||
else: # user mode, non-op_level mode
|
else: # user mode, non-op_level mode
|
||||||
continue
|
continue
|
||||||
|
@ -378,8 +357,8 @@ class Fulvia(irc.IRCClient):
|
||||||
print(f"Signed on as {self.nickname}")
|
print(f"Signed on as {self.nickname}")
|
||||||
self.whois(self.nickname)
|
self.whois(self.nickname)
|
||||||
|
|
||||||
line = "*** Signed onto " + self.hostname + " as "
|
line = f"*** Signed onto {self.hostname} as "
|
||||||
line += self.nickname + "!" + self.username + "@" + self.host
|
line += f"{self.nickname}!{self.username}@{self.host}"
|
||||||
self.log(self.hostname, line)
|
self.log(self.hostname, line)
|
||||||
|
|
||||||
for channel in self.config.core.channels.split(","):
|
for channel in self.config.core.channels.split(","):
|
||||||
|
@ -388,8 +367,8 @@ class Fulvia(irc.IRCClient):
|
||||||
|
|
||||||
def kickedFrom(self, channel, kicker, message):
|
def kickedFrom(self, channel, kicker, message):
|
||||||
"""Called when the bot is kicked from a channel."""
|
"""Called when the bot is kicked from a channel."""
|
||||||
line = "-!- " + self.nickname + " was kicked from " + channel
|
line = f"-!- {self.nickname} was kicked from {channel} "
|
||||||
line += " by " + kicker + " [" + message + "]"
|
line += f"by {kicker} [{message}]"
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
self.channels.pop(channel)
|
self.channels.pop(channel)
|
||||||
|
@ -397,16 +376,14 @@ class Fulvia(irc.IRCClient):
|
||||||
|
|
||||||
def nickChanged(self, nick):
|
def nickChanged(self, nick):
|
||||||
"""Called when the bot changes it's nickname."""
|
"""Called when the bot changes it's nickname."""
|
||||||
line = "-!- you are now known as " + nick
|
line = f"-!- you are now known as {nick}"
|
||||||
|
|
||||||
user = self.users.pop(self.nickname)
|
for channel_name, channel in self.channels.items():
|
||||||
self.users[nick] = user
|
|
||||||
for key, channel in self.channels.items():
|
|
||||||
self.log(key, line)
|
self.log(key, line)
|
||||||
|
|
||||||
channel.rename_user(self.nickname, nick)
|
user = channel.users.pop(self.nickname)
|
||||||
user.nick = nick
|
user.nick = nick
|
||||||
self.nickname = nick
|
channel.users[nick] = user
|
||||||
|
|
||||||
|
|
||||||
## Actions the bot observes other users doing in the channel.
|
## Actions the bot observes other users doing in the channel.
|
||||||
|
@ -416,12 +393,11 @@ class Fulvia(irc.IRCClient):
|
||||||
"""Called when the bot sees another user join a channel."""
|
"""Called when the bot sees another user join a channel."""
|
||||||
nick, _, host = user.partition("!")
|
nick, _, host = user.partition("!")
|
||||||
|
|
||||||
line = "-!- " + nick + " " + "[" + host + "] has joined " + channel
|
line = f"-!- {nick} [{host}] has joined {channel}"
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
if nick not in self.users:
|
user = tools.User(nick)
|
||||||
self.users[nick] = tools.User(nick)
|
self.channels[channel].users[nick] = user
|
||||||
self.channels[channel].add_user(self.users[nick])
|
|
||||||
|
|
||||||
for func in self._user_joined:
|
for func in self._user_joined:
|
||||||
trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG", self.config)
|
trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG", self.config)
|
||||||
|
@ -434,41 +410,38 @@ class Fulvia(irc.IRCClient):
|
||||||
"""Called when the bot sees another user leave a channel."""
|
"""Called when the bot sees another user leave a channel."""
|
||||||
nick, _, host = user.partition("!")
|
nick, _, host = user.partition("!")
|
||||||
|
|
||||||
line = "-!- " + nick + " " + "[" + host + "] has left "
|
line = f"-!- {nick} [{host}] has left {channel} [{reason}]"
|
||||||
line += channel + " [" + reason + "]"
|
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
self.channels[channel].remove_user(nick)
|
self.channels[channel].users.pop(nick)
|
||||||
|
|
||||||
|
|
||||||
def userQuit(self, user, quitMessage):
|
def userQuit(self, user, quitMessage):
|
||||||
"""Called when the bot sees another user disconnect from the network."""
|
"""Called when the bot sees another user disconnect from the network."""
|
||||||
nick, _, host = user.partition("!")
|
nick, _, host = user.partition("!")
|
||||||
line = "-!- " + nick + " [" + host + "] has quit [" + quitMessage + "]"
|
line = "-!- {nick} [{host}] has quit [{quitMessage}]"
|
||||||
|
|
||||||
channels = list(self.users[nick].channels.keys())
|
for channel_name, channel in self.channels.items():
|
||||||
for channel in channels:
|
if not nick in channel.users:
|
||||||
|
continue
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
self.channels[channel].remove_user(nick)
|
channel.users.pop(nick)
|
||||||
self.users.pop(nick)
|
|
||||||
|
|
||||||
|
|
||||||
def userKicked(self, kickee, channel, kicker, message):
|
def userKicked(self, kickee, channel, kicker, message):
|
||||||
"""
|
"""
|
||||||
Called when the bot sees another user getting kicked from the channel.
|
Called when the bot sees another user getting kicked from the channel.
|
||||||
"""
|
"""
|
||||||
line = "-!- " + kickee + " was kicked from " + channel
|
line =f"-!- {kickee} was kicked from {channel} by {kicker} [{message}]"
|
||||||
line += " by " + kicker + " [" + message + "]"
|
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
self.channels[channel].remove_user(kickee)
|
self.channels[channel].users.pop(kickee)
|
||||||
|
|
||||||
|
|
||||||
def topicUpdated(self, user, channel, newTopic):
|
def topicUpdated(self, user, channel, newTopic):
|
||||||
"""Called when the bot sees a user update the channel's topic."""
|
"""Called when the bot sees a user update the channel's topic."""
|
||||||
line = "-!- " + user + " changed the topic of " + channel + " to: "
|
line = f"-!- {user} changed the topic of {channel} to: {newTopic}"
|
||||||
line += newTopic
|
|
||||||
self.log(channel, line)
|
self.log(channel, line)
|
||||||
|
|
||||||
self.channels[channel].topic = newTopic
|
self.channels[channel].topic = newTopic
|
||||||
|
@ -476,15 +449,14 @@ class Fulvia(irc.IRCClient):
|
||||||
|
|
||||||
def userRenamed(self, oldname, newname):
|
def userRenamed(self, oldname, newname):
|
||||||
"""Called when the bot sees a user change their nickname."""
|
"""Called when the bot sees a user change their nickname."""
|
||||||
line = "-!- " + oldname + " is now known as " + newname
|
line = "-!- {oldname} is now known as {newname}"
|
||||||
|
|
||||||
user = self.users.pop(oldname)
|
for channel_name, channel in self.channels.items():
|
||||||
self.users[newname] = user
|
self.log(channel_name, line)
|
||||||
for key, channel in user.channels.items():
|
|
||||||
self.log(key, line)
|
|
||||||
|
|
||||||
channel.rename_user(oldname, newname)
|
user = channel.users.pop(oldname)
|
||||||
user.nick = newname
|
user.nick = newname
|
||||||
|
channel.users[newname] = user
|
||||||
|
|
||||||
|
|
||||||
def namesReceived(self, channel, channel_type, nicklist):
|
def namesReceived(self, channel, channel_type, nicklist):
|
||||||
|
@ -494,12 +466,13 @@ class Fulvia(irc.IRCClient):
|
||||||
"""
|
"""
|
||||||
self.channels[channel].channel_type = channel_type
|
self.channels[channel].channel_type = channel_type
|
||||||
for nick in nicklist:
|
for nick in nicklist:
|
||||||
op_level = tools.op_level.get(nick[0], 0)
|
op_level = ''
|
||||||
if op_level > 0:
|
if nick[0] in tools.op_level.keys():
|
||||||
|
op_level = nick[0]
|
||||||
nick = nick[1:]
|
nick = nick[1:]
|
||||||
self.users[nick] = tools.User(nick)
|
user = tools.User(nick)
|
||||||
self.channels[channel].add_user(self.users[nick])
|
user.op_level = op_level
|
||||||
self.channels[channel].privileges[nick] = op_level
|
self.channels[channel].users[nick] = user
|
||||||
|
|
||||||
|
|
||||||
def whoisUser(self, nick, ident, host, realname):
|
def whoisUser(self, nick, ident, host, realname):
|
||||||
|
@ -510,6 +483,13 @@ class Fulvia(irc.IRCClient):
|
||||||
self.username = ident
|
self.username = ident
|
||||||
self.host = host
|
self.host = host
|
||||||
self.realname = realname
|
self.realname = realname
|
||||||
|
else:
|
||||||
|
for channel_name, channel in self.channels.items():
|
||||||
|
if nick in channel:
|
||||||
|
user = channel[nick]
|
||||||
|
user.ident = ident
|
||||||
|
user.host = host
|
||||||
|
user.realname = realname
|
||||||
|
|
||||||
|
|
||||||
def whoisIdle(self, nick, idle, signon):
|
def whoisIdle(self, nick, idle, signon):
|
||||||
|
@ -534,11 +514,10 @@ class Fulvia(irc.IRCClient):
|
||||||
an appropriate length automatically.
|
an appropriate length automatically.
|
||||||
"""
|
"""
|
||||||
if user.startswith("#"):
|
if user.startswith("#"):
|
||||||
priv = self.channels[user].privileges[self.nickname]
|
opSym = self.channels[user].users[self.nickname].op_level
|
||||||
opSym = tools.getOpSym(priv)
|
|
||||||
else:
|
else:
|
||||||
opSym = ""
|
opSym = ''
|
||||||
line = "<" + opSym + self.nickname + ">" + " " + message
|
line = f"<{opSym}{self.nickname}> {message}"
|
||||||
self.log(user, line)
|
self.log(user, line)
|
||||||
|
|
||||||
irc.IRCClient.msg(self, user, message, length=None)
|
irc.IRCClient.msg(self, user, message, length=None)
|
||||||
|
|
27
loader.py
27
loader.py
|
@ -30,6 +30,7 @@ def unload_module(bot, name):
|
||||||
bot.unregister_callable(obj)
|
bot.unregister_callable(obj)
|
||||||
|
|
||||||
del old_module
|
del old_module
|
||||||
|
delattr(sys.modules['modules'], name.rpartition('.')[2])
|
||||||
del sys.modules[name]
|
del sys.modules[name]
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,36 +77,10 @@ def process_callable(func, config):
|
||||||
Sets various helper atributes about a given function.
|
Sets various helper atributes about a given function.
|
||||||
"""
|
"""
|
||||||
prefix = config.core.prefix
|
prefix = config.core.prefix
|
||||||
doc = func.__doc__
|
|
||||||
if doc:
|
|
||||||
doc = doc.strip()
|
|
||||||
doc = doc.replace("\t", "")
|
|
||||||
doc = doc.replace("\n\n", "\x00")
|
|
||||||
doc = doc.replace("\n", " ")
|
|
||||||
doc = doc.replace("\x00", "\n")
|
|
||||||
func._docs = {}
|
|
||||||
|
|
||||||
func.example = getattr(func, "example", [(None, None)])
|
|
||||||
func.thread = getattr(func, "thread", True)
|
func.thread = getattr(func, "thread", True)
|
||||||
func.hook = getattr(func, "hook", False)
|
func.hook = getattr(func, "hook", False)
|
||||||
func.rate = getattr(func, "rate", 0)
|
func.rate = getattr(func, "rate", 0)
|
||||||
func.channel_rate = getattr(func, "channel_rate", 0)
|
func.channel_rate = getattr(func, "channel_rate", 0)
|
||||||
func.global_rate = getattr(func, "global_rate", 0)
|
func.global_rate = getattr(func, "global_rate", 0)
|
||||||
func.priv = getattr(func, "priv", 0)
|
|
||||||
func.user_joined = getattr(func, "user_joined", False)
|
func.user_joined = getattr(func, "user_joined", False)
|
||||||
|
|
||||||
if hasattr(func, 'commands'):
|
|
||||||
if len(func.commands) > 1:
|
|
||||||
func.aliases = func.commands[1:]
|
|
||||||
else:
|
|
||||||
func.aliases = []
|
|
||||||
if hasattr(func, 'example'):
|
|
||||||
for n, example in enumerate(func.example):
|
|
||||||
ex_input = example[0]
|
|
||||||
if not ex_input:
|
|
||||||
continue
|
|
||||||
if ex_input[0] != prefix:
|
|
||||||
ex_input = prefix + ex_input
|
|
||||||
func.example[n] = (ex_input, example[1])
|
|
||||||
if doc:
|
|
||||||
func._docs = (doc, func.example)
|
|
||||||
|
|
34
module.py
34
module.py
|
@ -146,32 +146,6 @@ def require_chanmsg(message=None):
|
||||||
return actual_decorator
|
return actual_decorator
|
||||||
|
|
||||||
|
|
||||||
def require_privilege(level, message=None):
|
|
||||||
"""
|
|
||||||
Decorate a function to require at least the given channel permission.
|
|
||||||
|
|
||||||
`level` can be one of the privilege levels defined in this module. If the
|
|
||||||
user does not have the privilege, `message` will be said if given. If it is
|
|
||||||
a private message, no checking will be done.
|
|
||||||
"""
|
|
||||||
def actual_decorator(function):
|
|
||||||
function.priv = level
|
|
||||||
@functools.wraps(function)
|
|
||||||
def guarded(bot, trigger, *args, **kwargs):
|
|
||||||
# If this is a privmsg, ignore privilege requirements
|
|
||||||
if trigger.is_privmsg or trigger.admin:
|
|
||||||
return function(bot, trigger, *args, **kwargs)
|
|
||||||
channel_privs = bot.channels[trigger.channel].privileges
|
|
||||||
allowed = channel_privs.get(trigger.nick, 0) >= level
|
|
||||||
if not allowed:
|
|
||||||
if message and not callable(message):
|
|
||||||
bot.msg(message)
|
|
||||||
else:
|
|
||||||
return function(bot, trigger, *args, **kwargs)
|
|
||||||
return guarded
|
|
||||||
return actual_decorator
|
|
||||||
|
|
||||||
|
|
||||||
def require_admin(message=None):
|
def require_admin(message=None):
|
||||||
"""
|
"""
|
||||||
Decorate a function to require the triggering user to be a bot admin.
|
Decorate a function to require the triggering user to be a bot admin.
|
||||||
|
@ -179,8 +153,7 @@ def require_admin(message=None):
|
||||||
If they are not, `message` will be said if given.
|
If they are not, `message` will be said if given.
|
||||||
"""
|
"""
|
||||||
def actual_decorator(function):
|
def actual_decorator(function):
|
||||||
function.priv = 5
|
function.require_admin = True
|
||||||
|
|
||||||
@functools.wraps(function)
|
@functools.wraps(function)
|
||||||
def guarded(bot, trigger, *args, **kwargs):
|
def guarded(bot, trigger, *args, **kwargs):
|
||||||
if not trigger.admin:
|
if not trigger.admin:
|
||||||
|
@ -202,8 +175,7 @@ def require_owner(message=None):
|
||||||
If they are not, `message` will be said if given.
|
If they are not, `message` will be said if given.
|
||||||
"""
|
"""
|
||||||
def actual_decorator(function):
|
def actual_decorator(function):
|
||||||
function.priv = 10
|
function.require_owner = True
|
||||||
|
|
||||||
@functools.wraps(function)
|
@functools.wraps(function)
|
||||||
def guarded(bot, trigger, *args, **kwargs):
|
def guarded(bot, trigger, *args, **kwargs):
|
||||||
if not trigger.owner:
|
if not trigger.owner:
|
||||||
|
@ -236,7 +208,7 @@ def example(ex_input, ex_output=None):
|
||||||
|
|
||||||
def url_callback(url):
|
def url_callback(url):
|
||||||
"""
|
"""
|
||||||
Decore a function with a callback to the URL module.
|
Decorate a function with a callback to the URL module.
|
||||||
|
|
||||||
This URL will be added to the bot.url_callbacks dictionary in the bot's
|
This URL will be added to the bot.url_callbacks dictionary in the bot's
|
||||||
memory which the URL module will compare it's URL's against. If a key in
|
memory which the URL module will compare it's URL's against. If a key in
|
||||||
|
|
|
@ -26,13 +26,11 @@ def new_bot_name(number):
|
||||||
@user_joined(True)
|
@user_joined(True)
|
||||||
def adalwulf_(bot, trigger):
|
def adalwulf_(bot, trigger):
|
||||||
"""Renames adalwulf__."""
|
"""Renames adalwulf__."""
|
||||||
print(True)
|
|
||||||
print(trigger.nick)
|
|
||||||
if not trigger.nick.startswith('defaultnick'):
|
if not trigger.nick.startswith('defaultnick'):
|
||||||
return
|
return
|
||||||
names = bot.channels[trigger.channel].users
|
nicks = bot.channels[trigger.channel].users.keys()
|
||||||
adals = [nick for nick in names if nick.startswith('Adalwulf__')]
|
adals = [nick for nick in nicks if nick.startswith('Adalwulf__')]
|
||||||
adals += [nick for nick in names if nick.startswith('Adalwulf_|')]
|
adals += [nick for nick in nicks if nick.startswith('Adalwulf_|')]
|
||||||
old_nick = trigger.nick
|
old_nick = trigger.nick
|
||||||
new_nick = new_bot_name(len(adals) + 1)
|
new_nick = new_bot_name(len(adals) + 1)
|
||||||
bot.sendLine(f"SANICK {old_nick} {new_nick}")
|
bot.sendLine(f"SANICK {old_nick} {new_nick}")
|
||||||
|
@ -42,12 +40,12 @@ def adalwulf_(bot, trigger):
|
||||||
@commands('rename_hydra')
|
@commands('rename_hydra')
|
||||||
def rename_hydra(bot, trigger):
|
def rename_hydra(bot, trigger):
|
||||||
"""Renames defaultnick's appropriately."""
|
"""Renames defaultnick's appropriately."""
|
||||||
for nick in list(bot.channels[trigger.channel].users.keys()):
|
for nick in bot.channels[trigger.channel].users.keys():
|
||||||
if not nick.startswith('defaultnick'):
|
if not nick.startswith('defaultnick'):
|
||||||
continue
|
continue
|
||||||
names = bot.channels[trigger.channel].users
|
nicks = bot.channels[trigger.channel].users.keys()
|
||||||
adals = [nick for nick in names if nick.startswith('Adalwulf__')]
|
adals = [nick for nick in nicks if nick.startswith('Adalwulf__')]
|
||||||
adals += [nick for nick in names if nick.startswith('Adalwulf_|')]
|
adals += [nick for nick in nicks if nick.startswith('Adalwulf_|')]
|
||||||
old_nick = nick
|
old_nick = nick
|
||||||
new_nick = new_bot_name(len(adals) + 1)
|
new_nick = new_bot_name(len(adals) + 1)
|
||||||
print(f"SANICK {old_nick} {new_nick}")
|
print(f"SANICK {old_nick} {new_nick}")
|
||||||
|
|
|
@ -9,18 +9,17 @@ import re
|
||||||
import module
|
import module
|
||||||
from tools import op_level, configureHostMask
|
from tools import op_level, configureHostMask
|
||||||
|
|
||||||
OP = op_level["op"]
|
op = ['~', '!', '@', '%']
|
||||||
HALFOP = op_level["halfop"]
|
|
||||||
|
|
||||||
@module.require_chanmsg
|
@module.require_chanmsg
|
||||||
@module.require_privilege(OP, 'You are not a channel operator.')
|
@module.require_admin
|
||||||
@module.commands('kick')
|
@module.commands('kick')
|
||||||
@module.example(".kick faggot being a faggot")
|
@module.example(".kick faggot being a faggot")
|
||||||
def kick(bot, trigger):
|
def kick(bot, trigger):
|
||||||
"""
|
"""
|
||||||
Kick a user from the channel.
|
Kick a user from the channel.
|
||||||
"""
|
"""
|
||||||
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP:
|
if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
|
||||||
return bot.reply("I'm not a channel operator!")
|
return bot.reply("I'm not a channel operator!")
|
||||||
if not trigger.group(2):
|
if not trigger.group(2):
|
||||||
return bot.reply("Who do you want me to kick?")
|
return bot.reply("Who do you want me to kick?")
|
||||||
|
@ -36,7 +35,7 @@ def kick(bot, trigger):
|
||||||
|
|
||||||
|
|
||||||
@module.require_chanmsg
|
@module.require_chanmsg
|
||||||
@module.require_privilege(OP, 'You are not a channel operator.')
|
@module.require_admin
|
||||||
@module.commands('ban')
|
@module.commands('ban')
|
||||||
@module.example(".ban faggot")
|
@module.example(".ban faggot")
|
||||||
def ban(bot, trigger):
|
def ban(bot, trigger):
|
||||||
|
@ -44,7 +43,7 @@ def ban(bot, trigger):
|
||||||
This give admins the ability to ban a user.
|
This give admins the ability to ban a user.
|
||||||
The bot must be a Channel Operator for this command to work.
|
The bot must be a Channel Operator for this command to work.
|
||||||
"""
|
"""
|
||||||
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP:
|
if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
|
||||||
return bot.reply("I'm not a channel operator!")
|
return bot.reply("I'm not a channel operator!")
|
||||||
if not trigger.group(2):
|
if not trigger.group(2):
|
||||||
return bot.reply("Who do you want me to ban?")
|
return bot.reply("Who do you want me to ban?")
|
||||||
|
@ -54,7 +53,7 @@ def ban(bot, trigger):
|
||||||
|
|
||||||
|
|
||||||
@module.require_chanmsg
|
@module.require_chanmsg
|
||||||
@module.require_privilege(OP, 'You are not a channel operator.')
|
@module.require_admin
|
||||||
@module.commands('unban')
|
@module.commands('unban')
|
||||||
@module.example(".unban faggot")
|
@module.example(".unban faggot")
|
||||||
def unban(bot, trigger):
|
def unban(bot, trigger):
|
||||||
|
@ -62,7 +61,7 @@ def unban(bot, trigger):
|
||||||
This give admins the ability to unban a user.
|
This give admins the ability to unban a user.
|
||||||
The bot must be a Channel Operator for this command to work.
|
The bot must be a Channel Operator for this command to work.
|
||||||
"""
|
"""
|
||||||
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP:
|
if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
|
||||||
return bot.reply("I'm not a channel operator!")
|
return bot.reply("I'm not a channel operator!")
|
||||||
if not trigger.group(2):
|
if not trigger.group(2):
|
||||||
return bot.reply("Who do you want me to ban?")
|
return bot.reply("Who do you want me to ban?")
|
||||||
|
@ -72,7 +71,7 @@ def unban(bot, trigger):
|
||||||
|
|
||||||
|
|
||||||
@module.require_chanmsg
|
@module.require_chanmsg
|
||||||
@module.require_privilege(OP, 'You are not a channel operator.')
|
@module.require_admin
|
||||||
@module.commands('kickban')
|
@module.commands('kickban')
|
||||||
def kickban(bot, trigger):
|
def kickban(bot, trigger):
|
||||||
"""
|
"""
|
||||||
|
@ -80,7 +79,7 @@ def kickban(bot, trigger):
|
||||||
The bot must be a Channel Operator for this command to work.
|
The bot must be a Channel Operator for this command to work.
|
||||||
.kickban [#chan] user1 user!*@module.* get out of here
|
.kickban [#chan] user1 user!*@module.* get out of here
|
||||||
"""
|
"""
|
||||||
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP:
|
if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
|
||||||
return bot.reply("I'm not a channel operator!")
|
return bot.reply("I'm not a channel operator!")
|
||||||
if not trigger.group(2):
|
if not trigger.group(2):
|
||||||
return bot.reply("Who do you want me to ban?")
|
return bot.reply("Who do you want me to ban?")
|
||||||
|
@ -98,7 +97,7 @@ def kickban(bot, trigger):
|
||||||
|
|
||||||
|
|
||||||
@module.require_chanmsg
|
@module.require_chanmsg
|
||||||
@module.require_privilege(OP, 'You are not a channel operator.')
|
@module.require_admin
|
||||||
@module.commands('settopic')
|
@module.commands('settopic')
|
||||||
@module.example(".settopic We're discussing penises, would you like to join?")
|
@module.example(".settopic We're discussing penises, would you like to join?")
|
||||||
def settopic(bot, trigger):
|
def settopic(bot, trigger):
|
||||||
|
@ -106,7 +105,7 @@ def settopic(bot, trigger):
|
||||||
This gives ops the ability to change the topic.
|
This gives ops the ability to change the topic.
|
||||||
The bot must be a Channel Operator for this command to work.
|
The bot must be a Channel Operator for this command to work.
|
||||||
"""
|
"""
|
||||||
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP:
|
if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
|
||||||
return bot.reply("I'm not a channel operator!")
|
return bot.reply("I'm not a channel operator!")
|
||||||
if not trigger.group(2):
|
if not trigger.group(2):
|
||||||
return bot.reply("What do you want the topic set to?")
|
return bot.reply("What do you want the topic set to?")
|
||||||
|
|
|
@ -14,6 +14,6 @@ def announce(bot, trigger):
|
||||||
if not trigger.admin:
|
if not trigger.admin:
|
||||||
bot.reply("Sorry, I can't let you do that")
|
bot.reply("Sorry, I can't let you do that")
|
||||||
return
|
return
|
||||||
for channel in bot.channels:
|
for channel in bot.channels.keys():
|
||||||
bot.msg(channel, f"[ANNOUNCEMENT] {trigger.group(2)}")
|
bot.msg(channel, f"[ANNOUNCEMENT] {trigger.group(2)}")
|
||||||
bot.reply('Announce complete.')
|
bot.reply('Announce complete.')
|
||||||
|
|
|
@ -54,7 +54,7 @@ def banheall(bot, trigger):
|
||||||
except (IndexError, KeyError, ValueError, TypeError):
|
except (IndexError, KeyError, ValueError, TypeError):
|
||||||
period = 0
|
period = 0
|
||||||
|
|
||||||
for nick in bot.channels[trigger.channel].users:
|
for nick in bot.channels[trigger.channel].users.keys():
|
||||||
banmask = configureHostMask(nick)
|
banmask = configureHostMask(nick)
|
||||||
bot.mode(trigger.channel, True, "b", mask=banmask)
|
bot.mode(trigger.channel, True, "b", mask=banmask)
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ def banheall(bot, trigger):
|
||||||
bot.msg(f"Banned \x0304them all\x03 for \x0309{str(period)}\x03 seconds.")
|
bot.msg(f"Banned \x0304them all\x03 for \x0309{str(period)}\x03 seconds.")
|
||||||
time.sleep(period)
|
time.sleep(period)
|
||||||
|
|
||||||
for nick in bot.channels[trigger.channel].users:
|
for nick in bot.channels[trigger.channel].users.keys():
|
||||||
banmask = configureHostMask(nick)
|
banmask = configureHostMask(nick)
|
||||||
bot.mode(trigger.channel, False, "b", mask=banmask)
|
bot.mode(trigger.channel, False, "b", mask=banmask)
|
||||||
|
|
||||||
|
|
|
@ -7,38 +7,50 @@ import random
|
||||||
|
|
||||||
from module import commands, example
|
from module import commands, example
|
||||||
|
|
||||||
|
def clean_docstring(doc):
|
||||||
|
"""Cleans the docstring up a bit."""
|
||||||
|
if not doc:
|
||||||
|
return ''
|
||||||
|
doc = doc.strip()
|
||||||
|
doc = doc.replace("\t", "")
|
||||||
|
doc = doc.replace("\n\n", "\x00")
|
||||||
|
doc = doc.replace("\n", " ")
|
||||||
|
doc = doc.replace("\x00", "\n")
|
||||||
|
return doc
|
||||||
|
|
||||||
@commands('help', 'commands')
|
@commands('help', 'commands')
|
||||||
@example('.help tell')
|
@example('.help tell')
|
||||||
def help(bot, trigger):
|
def help(bot, trigger):
|
||||||
"""Shows a command's documentation, and possibly an example."""
|
"""Shows a command's documentation, and possibly an example."""
|
||||||
if trigger.group(2):
|
if trigger.group(2):
|
||||||
name = trigger.group(2)
|
command = trigger.group(2)
|
||||||
name = name.lower()
|
command = command.lower()
|
||||||
if name not in bot.commands:
|
if command not in bot.commands:
|
||||||
return bot.msg("Command not found.")
|
return bot.msg("Command not found.")
|
||||||
cmd = bot.commands[name]
|
|
||||||
docstring, examples = cmd.doc
|
|
||||||
if examples:
|
|
||||||
ex = random.choice(examples)
|
|
||||||
|
|
||||||
bot.msg(docstring)
|
func = bot.commands[command]
|
||||||
if cmd.aliases:
|
doc = clean_docstring(func.__doc__)
|
||||||
bot.msg("Aliases: " + ", ".join(cmd.aliases))
|
bot.msg(doc)
|
||||||
if ex[0]:
|
|
||||||
|
aliases = [c for c, f in bot.commands.items() if f == func]
|
||||||
|
aliases.remove(command)
|
||||||
|
if aliases:
|
||||||
|
bot.msg("Aliases: " + ", ".join(aliases))
|
||||||
|
|
||||||
|
if hasattr(func, 'example'):
|
||||||
|
ex = random.choice(func.example)
|
||||||
bot.msg("Ex. In: " + ex[0])
|
bot.msg("Ex. In: " + ex[0])
|
||||||
if ex[1]:
|
if ex[1]:
|
||||||
bot.msg("Ex. Out: " + ex[1])
|
bot.msg("Ex. Out: " + ex[1])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if trigger.owner:
|
funcs = [func for cmd, func in bot.commands.items()]
|
||||||
cmds = [cmd for _, cmd in bot.commands.items()]
|
if not trigger.owner:
|
||||||
elif trigger.admin:
|
funcs = [f for f in funcs if not hasattr(f, 'require_owner')]
|
||||||
cmds = [cmd for _, cmd in bot.commands.items() if cmd.priv <= 5]
|
if not trigger.admin:
|
||||||
else:
|
funcs = [f for f in funcs if not hasattr(f, 'require_admin')]
|
||||||
priv = bot.channels[trigger.channel].privileges[trigger.nick]
|
|
||||||
cmds = [cmd for _, cmd in bot.commands.items() if cmd.priv <= priv]
|
|
||||||
|
|
||||||
cmds = [cmd.name for cmd in cmds if cmd.canonical]
|
cmds = {func.commands[0] for func in funcs}
|
||||||
cmds = sorted(cmds)
|
cmds = sorted(list(cmds))
|
||||||
msg = "Available commands: " + ", ".join(cmds)
|
msg = "Available commands: " + ", ".join(cmds)
|
||||||
bot.msg(msg)
|
bot.msg(msg)
|
||||||
|
|
|
@ -10,8 +10,8 @@ def pingAll(bot, trigger):
|
||||||
Says the nick of everyone in the channel. Great way to get thier
|
Says the nick of everyone in the channel. Great way to get thier
|
||||||
attention, or just annoy them.
|
attention, or just annoy them.
|
||||||
"""
|
"""
|
||||||
names = list(bot.channels[trigger.channel].users.keys())
|
nicks = list(bot.channels[trigger.channel].users.keys())
|
||||||
for nigger in ["Ishd", "Ishd2", "Ishd_"]:
|
for nigger in ["Ishd", "Ishd2", "Ishd_"]:
|
||||||
if nigger in names:
|
if nigger in nicks:
|
||||||
names.remove(nigger)
|
nicks.remove(nigger)
|
||||||
bot.msg(" ".join(names))
|
bot.msg(" ".join(nicks))
|
||||||
|
|
|
@ -72,4 +72,4 @@ def f_unload(bot, trigger):
|
||||||
return bot.msg(f"Module '{name}' not loaded, try the 'load' command.")
|
return bot.msg(f"Module '{name}' not loaded, try the 'load' command.")
|
||||||
|
|
||||||
loader.unload_module(bot, name)
|
loader.unload_module(bot, name)
|
||||||
bot.msg(f"Module '{name}' unloaded.")
|
bot.msg(f"Module '{name}' unloaded.")
|
||||||
|
|
|
@ -24,7 +24,6 @@ class MonitorThread(threading.Thread):
|
||||||
self.stop = threading.Event()
|
self.stop = threading.Event()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# while not self._bot.channels.keys():
|
|
||||||
while not self._bot.stillConnected():
|
while not self._bot.stillConnected():
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# don't try to say anything if we're not fully connected yet
|
# don't try to say anything if we're not fully connected yet
|
||||||
|
|
|
@ -111,8 +111,8 @@ class FulviaMemoryDefault(defaultdict):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class User(object):
|
class User:
|
||||||
"""A representation of a user Fulvia is aware of."""
|
"""A representation of a user in a channel."""
|
||||||
def __init__(self, nick):
|
def __init__(self, nick):
|
||||||
self.nick = nick
|
self.nick = nick
|
||||||
"""The user's nickname."""
|
"""The user's nickname."""
|
||||||
|
@ -124,18 +124,21 @@ class User(object):
|
||||||
self.host = ""
|
self.host = ""
|
||||||
"""The user's hostname."""
|
"""The user's hostname."""
|
||||||
|
|
||||||
self.channels = {}
|
self.realname = ""
|
||||||
"""The channels the user is in."""
|
"""The user's realname."""
|
||||||
|
|
||||||
self.away = None
|
self.away = None
|
||||||
"""Whether the user is marked as away."""
|
"""Whether the user is marked as away."""
|
||||||
|
|
||||||
hostmask = property(lambda self: '{}!{}@{}'.format(self.nick, self.user,
|
self.op_level = ''
|
||||||
self.host))
|
"""The user's op level in this channel."""
|
||||||
"""The user's full hostmask."""
|
|
||||||
|
def hostmask(self):
|
||||||
|
"""Returns the user's full hostmask."""
|
||||||
|
return f"{self.nick}!{self.user}@{self.host}"
|
||||||
|
|
||||||
|
|
||||||
class Channel(object):
|
class Channel:
|
||||||
"""A representation of a channel Fulvia is in."""
|
"""A representation of a channel Fulvia is in."""
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -151,55 +154,11 @@ class Channel(object):
|
||||||
"""The topic of the channel."""
|
"""The topic of the channel."""
|
||||||
|
|
||||||
self.users = {}
|
self.users = {}
|
||||||
"""The users in the channel. A set to ensure there are no duplicates."""
|
"""The users in the channel."""
|
||||||
|
|
||||||
self.privileges = {}
|
|
||||||
"""The op levels of the users in the channel."""
|
|
||||||
|
|
||||||
self.modes = set()
|
self.modes = set()
|
||||||
"""The current modes on the channel."""
|
"""The current modes on the channel."""
|
||||||
|
|
||||||
def remove_user(self, nick):
|
|
||||||
"""
|
|
||||||
Removes a user from the channel.
|
|
||||||
"""
|
|
||||||
user = self.users.pop(nick, None)
|
|
||||||
self.privileges.pop(nick, None)
|
|
||||||
if user != None:
|
|
||||||
user.channels.pop(self.name, None)
|
|
||||||
|
|
||||||
def add_user(self, user):
|
|
||||||
"""
|
|
||||||
Adds a user to the channel.
|
|
||||||
"""
|
|
||||||
assert isinstance(user, User)
|
|
||||||
self.users[user.nick] = user
|
|
||||||
self.privileges[user.nick] = 0
|
|
||||||
user.channels[self.name] = self
|
|
||||||
|
|
||||||
def rename_user(self, old, new):
|
|
||||||
"""
|
|
||||||
Renames the user.
|
|
||||||
"""
|
|
||||||
if old in self.users:
|
|
||||||
self.users[new] = self.users.pop(old)
|
|
||||||
if old in self.privileges:
|
|
||||||
self.privileges[new] = self.privileges.pop(old)
|
|
||||||
|
|
||||||
|
|
||||||
class Command():
|
|
||||||
"""
|
|
||||||
A representation of a command and associated documentation and other
|
|
||||||
atributes.
|
|
||||||
"""
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
self._func_name = ""
|
|
||||||
self.priv = 0
|
|
||||||
self.doc = None
|
|
||||||
self.canonical = True
|
|
||||||
self.aliases = []
|
|
||||||
|
|
||||||
|
|
||||||
def configureHostMask(mask):
|
def configureHostMask(mask):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user